How to coerce a list of list to a tibble

I have a list of list like the following:

alist <- list(
  product1 = list(date = seq(from = 0, to = 10, by = 1),
       value = seq(from = 100, to = 110, by = 1)),
  product2 = list(date = seq(from = 0, to = 15, by = 1),
                  value = seq(from = 200, to = 215, by = 1))
)

And I need to coerce it to a tibble, where the output should be like it:

tibble(
  date = seq(from = 0, to = 15, by = 1),
  product1 = c(seq(from = 100, to = 110, by = 1), rep(NA,5)),
  product2 = seq(from = 200, to = 215, by = 1),
)

But note that the product1 list is smaller than product2 list.

How can I do it?

1 Like

I love this question! It really shows a place where {purrr} can shine:

library(tidyverse)

# Start
alist <- list(
  product1 = list(date = seq(from = 0, to = 10, by = 1),
                  value = seq(from = 100, to = 110, by = 1)),
  product2 = list(date = seq(from = 0, to = 15, by = 1),
                  value = seq(from = 200, to = 215, by = 1))
)

# Goal
tibble(
  date = seq(from = 0, to = 15, by = 1),
  product1 = c(seq(from = 100, to = 110, by = 1), rep(NA,5)),
  product2 = seq(from = 200, to = 215, by = 1),
)
#> # A tibble: 16 x 3
#>     date product1 product2
#>    <dbl>    <dbl>    <dbl>
#>  1     0      100      200
#>  2     1      101      201
#>  3     2      102      202
#>  4     3      103      203
#>  5     4      104      204
#>  6     5      105      205
#>  7     6      106      206
#>  8     7      107      207
#>  9     8      108      208
#> 10     9      109      209
#> 11    10      110      210
#> 12    11       NA      211
#> 13    12       NA      212
#> 14    13       NA      213
#> 15    14       NA      214
#> 16    15       NA      215

# Solution
alist %>% 
  map(as_tibble) %>% 
  imap(~as_tibble(.x) %>% transmute(date, !!.y := value)) %>% 
  reduce(full_join, by = "date")
#> # A tibble: 16 x 3
#>     date product1 product2
#>    <dbl>    <dbl>    <dbl>
#>  1     0      100      200
#>  2     1      101      201
#>  3     2      102      202
#>  4     3      103      203
#>  5     4      104      204
#>  6     5      105      205
#>  7     6      106      206
#>  8     7      107      207
#>  9     8      108      208
#> 10     9      109      209
#> 11    10      110      210
#> 12    11       NA      211
#> 13    12       NA      212
#> 14    13       NA      213
#> 15    14       NA      214
#> 16    15       NA      215

Created on 2021-05-21 by the reprex package (v2.0.0)

2 Likes

I have a slightly different solution but similar ideas.

library(tidyverse)

alist <- list(
   product1 = list(date = seq(from = 0, to = 10, by = 1),
                   value = seq(from = 100, to = 110, by = 1)),
   product2 = list(date = seq(from = 0, to = 15, by = 1),
                   value = seq(from = 200, to = 215, by = 1))
)

# This function renames value to a new name
rnf <- function(df, newname){
   rename(df, {{newname}}:=value)
}

# alist2 is a list of tibbles now
alist2 <- alist %>% map(as_tibble) %>% map2(names(alist), rnf)
alist2
#> $product1
#> # A tibble: 11 x 2
#>     date product1
#>    <dbl>    <dbl>
#>  1     0      100
#>  2     1      101
#>  3     2      102
#>  4     3      103
#>  5     4      104
#>  6     5      105
#>  7     6      106
#>  8     7      107
#>  9     8      108
#> 10     9      109
#> 11    10      110
#> 
#> $product2
#> # A tibble: 16 x 2
#>     date product2
#>    <dbl>    <dbl>
#>  1     0      200
#>  2     1      201
#>  3     2      202
#>  4     3      203
#>  5     4      204
#>  6     5      205
#>  7     6      206
#>  8     7      207
#>  9     8      208
#> 10     9      209
#> 11    10      210
#> 12    11      211
#> 13    12      212
#> 14    13      213
#> 15    14      214
#> 16    15      215

# 
alist2 %>% reduce(full_join, by="date")
#> # A tibble: 16 x 3
#>     date product1 product2
#>    <dbl>    <dbl>    <dbl>
#>  1     0      100      200
#>  2     1      101      201
#>  3     2      102      202
#>  4     3      103      203
#>  5     4      104      204
#>  6     5      105      205
#>  7     6      106      206
#>  8     7      107      207
#>  9     8      108      208
#> 10     9      109      209
#> 11    10      110      210
#> 12    11       NA      211
#> 13    12       NA      212
#> 14    13       NA      213
#> 15    14       NA      214
#> 16    15       NA      215

Created on 2021-05-21 by the reprex package (v2.0.0)

2 Likes

And I was thinking a bit more about this. You could make a long tibble by stacking the data and then make it wider as follows:

library(tidyverse)

alist <- list(
   product1 = list(date = seq(from = 0, to = 10, by = 1),
                   value = seq(from = 100, to = 110, by = 1)),
   product2 = list(date = seq(from = 0, to = 15, by = 1),
                   value = seq(from = 200, to = 215, by = 1))
)

alist %>% 
   map(as_tibble) %>% 
   bind_rows(.id="id") %>%
   pivot_wider(names_from="id", values_from="value")
#> # A tibble: 16 x 3
#>     date product1 product2
#>    <dbl>    <dbl>    <dbl>
#>  1     0      100      200
#>  2     1      101      201
#>  3     2      102      202
#>  4     3      103      203
#>  5     4      104      204
#>  6     5      105      205
#>  7     6      106      206
#>  8     7      107      207
#>  9     8      108      208
#> 10     9      109      209
#> 11    10      110      210
#> 12    11       NA      211
#> 13    12       NA      212
#> 14    13       NA      213
#> 15    14       NA      214
#> 16    15       NA      215

Created on 2021-05-21 by the reprex package (v2.0.0)

4 Likes

@willmjr if any of these answered your problem, would you mind marking it as a solution? That will help others know this question has been answered.

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.