converting lists to tibbles (curly brackets + map())

Hi everyone (and thank you in advance for you time :)). I am working with purrr
and have a question about converting a list to a tibble. Below is an example list:


my_list <- list(
         x = 1.5, 
         y = c(2), 
         z = "A"),
         x = 4.2, 
         y = c(5, 6), 
         z = "B"),
         x = 8.8, 
         y = c(9, 10, 11))

When I pipe my_list to tibble() directly with purrr::map(), I get the following output:

my_list %>% 
    tibble(x = map(., "x"),
           y = map(., "y"),
           z = map(., "z"))
#> # A tibble: 3 × 4
#>   .                x         y         z        
#>   <list>           <list>    <list>    <list>   
#> 1 <named list [4]> <dbl [1]> <dbl [1]> <chr [1]>
#> 2 <named list [4]> <dbl [1]> <dbl [2]> <chr [1]>
#> 3 <named list [3]> <dbl [1]> <dbl [3]> <NULL>

This . is a column with 'named list' contents, but I am not sure why the . is included in the construction of the tibble? I know I can remove this behavior by adding some curly brackets:

my_list %>% { # <- magic? 
    tibble(x = map(., "x"),
           y = map(., "y"),
           z = map(., "z"))}
#> # A tibble: 3 × 3
#>   x         y         z        
#>   <list>    <list>    <list>   
#> 1 <dbl [1]> <dbl [1]> <chr [1]>
#> 2 <dbl [1]> <dbl [2]> <chr [1]>
#> 3 <dbl [1]> <dbl [3]> <NULL>

So, I know how to get the behavior I want, but I am not sure why I get this behavior. Any help or explanation would be greatly appreciated!

Thank you!

Created on 2022-01-03 by the reprex package (v2.0.1)

Hi there!

The difference is subtle. It helps understanding what %>% actually does. It takes whats left of it as a first argument to whats right of it. This argument is named .. In your first example, you pass my_list as . to the function tibble() as its first argument. so what's actually happening is that you call

       x = map(my_list, "x"),
       y = map(my_list, "y"),
       z = map(my_list, "z"))

If you look closely at your result, you see, that you have a so-called 'nested' tibble with the first column being your original list of list and the second list of the other list elements.

In the second case, what you pass my_list to is actually not a function but a closure, again . is the passed on my_list. What happens is:

 tibble(x = map(my_list, "x"),
        y = map(my_list, "y"),
        z = map(my_list, "z"))

In both cases, however, the classes of the columns are, still lists! See in the output after the column names. So you'll still need to fix that by running tidyr::unnest() afterwards, or by fixing the calls to map() to also extract the values properly.

Hope this helps!


This topic was automatically closed 21 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.