Search code examples
rdataframetidyrtibble

Unpacking a list-column of multi-row tibbles while preserving the number of rows


I have a tibble in which one column is a list of tibbles. Some tibbles in this list have more than one row. Here is a minimal example:

library(tibble)
tmp <- tribble(
  ~x, ~y,
   1,  tibble(a=1,   b=2),
   2,  tibble(a=4:5, b=6:7))

which produces

> tmp 
# A tibble: 2 x 2
      x y               
  <dbl> <list>          
1     1 <tibble [1 x 2]>
2     2 <tibble [2 x 2]>

I want to create a tibble that has the same number of rows as tmp and that expands the list-column into as many columns as necessary. In the example, I want

      x      a1      a2      b1      b2
  <int>   <dbl>   <dbl>   <dbl>   <dbl>
1     1       1      NA       2      NA
2     2       4       5       6       7

I had thought to do this with some combination of unnest() and pivot_wider(), or perhaps flatten(), but I cannot quite get it to work. What is the best way to do this?

In this example, the tibbles in the list-column never have more than two rows. But in my real list-columns, some tibbles have one row, some have two, and some have more than two. So I am looking for a solution that works when the tibbles in the list-column have any arbitrary number of rows.


Solution

  • Here's one solution using unnest_wider

    library(tidyr)
    unnest_wider(tmp, y) %>% 
          unnest_wider(a, names_repair = ~gsub('...', 'a', .)) %>% 
          unnest_wider(b, names_repair = ~gsub('...', 'b', .))
    
    New names:
    * `` -> ...1
    ...
    New names:
    * `` -> ...1
    * `` -> ...2
    # A tibble: 2 x 5
          x    a1    a2    b1    b2
      <dbl> <dbl> <int> <dbl> <int>
    1     1     1    NA     2    NA
    2     2     4     5     6     7