2
votes

I have the following list:

my_list = list(alpha = list('hi'), 
               beta = list(1:4, 'how'), 
               gamma = list(TRUE, FALSE, 'are'))
str(my_list)

List of 3
 $ alpha:List of 1
  ..$ : chr "hi"
 $ beta :List of 2
  ..$ : int [1:4] 1 2 3 4
  ..$ : chr "how"
 $ gamma:List of 3
  ..$ : logi TRUE
  ..$ : logi FALSE
  ..$ : chr "are"

I would like to figure out which data types are contained within each level 1 element. To do this, I can use the following pipeline:

piped = map(my_list, ~map(., class) %>% unique %>% unlist)
str(piped)
List of 3
 $ alpha: chr "character"
 $ beta : chr [1:2] "integer" "character"
 $ gamma: chr [1:2] "logical" "character"

...which works as expected. But when I try to nest the call to unique inside unlist(), I get something different:

composite = map(my_list, ~map(., class) %>% unlist(unique(.)))
str(composite)
List of 3
 $ alpha: chr "character"
 $ beta : chr [1:2] "integer" "character"
 $ gamma: chr [1:3] "logical" "logical" "character"

Could someone please help me understand why these two approaches are not equivalent?

1
I think the two uses of the dot are in different scopes, leading to the unexpected behavior but can't quite tease it out. - pgcudahy
Thanks for your input @pgcudahy, I tried using unique(.x) in place of unique(.) but got the same result. - user51462

1 Answers

3
votes

It's easier to see what's happening if you use anonymous functions rather than the dot notation.

piped = map(my_list, ~map(., class) %>% unique %>% unlist) is the same as

piped = map(my_list, function (x) map(x, class) %>% unique %>% unlist)

The pipe then places the output of each step in the first position of each subsequent function, so it becomes

piped = map(my_list, function (x) unique(map(x, class)) %>% unlist) and then

piped = map(my_list, function (x) unlist(unique(map(x, class))))

Which results is

str(piped)
List of 3
 $ alpha: chr "character"
 $ beta : chr [1:2] "integer" "character"
 $ gamma: chr [1:2] "logical" "character"

Similarly composite = map(my_list, ~map(., class) %>% unlist(unique(.)))

can be written as

composite = map(my_list, function(x) map(x, class) %>% unlist(unique(x)))

The two uses of x on both sides of the pipe is where things go weird. I think you were expecting the pipe to place the output of the inner map call in place of the x within the unique call, but the second x takes the output from the outer map function. Instead the pipe does its default action and places the output of the inner map call in the first position of the unlist function, like so

composite = map(my_list, function(x) unlist(map(x, class),unique(x)))

Which gives you

str(composite)
List of 3
 $ alpha: chr "character"
 $ beta : chr [1:2] "integer" "character"
 $ gamma: chr [1:3] "logical" "logical" "character"