Transform list of lists to redundant table

Imagine a list of lists like this:

list.test <- list(
    list( id = "a", values = c(1, 2, 3) )
  , list( id = "b", values = c(78, 99) )
)

I need to generate a matrix / data.frame like this:

      id      values
1  a        1
2  a        2
3  a        3
4  b        78
5  c         99

I already tried

as.data.frame(do.call( rbind, list.test))

which gives at least:

        id    values
1     a      1, 2, 3
2     b      78, 99

Any idea how to achieve this (preferably without loops)?

Thanks in advance

Markus

Got it with

tidyr::unnest(as.data.frame(do.call(rbind, list.test)), cols = values)

data.frame will automatically combine/cross the columns, so you could use this instead, where map_dfr combines the new data frames by row binding:

suppressMessages(library("tidyverse"))

list.test <- list(
  list( id = "a", values = c(1, 2, 3) )
  , list( id = "b", values = c(78, 99) )
)

map_dfr(list.test, ~unnest(data.frame(.), cols = c("id", "values")))
#> # A tibble: 5 x 2
#>   id    values
#>   <chr>  <dbl>
#> 1 a          1
#> 2 a          2
#> 3 a          3
#> 4 b         78
#> 5 b         99

Created on 2021-09-07 by the reprex package (v2.0.0)

Update (again): Actually, you do not even need the unnest or the data.frame parts, so an even shorter version is below:

suppressMessages(library("tidyverse"))

list.test <- list(
  list( id = "a", values = c(1, 2, 3) )
  , list( id = "b", values = c(78, 99) )
)

map_dfr(list.test, ~.)
#> # A tibble: 5 x 2
#>   id    values
#>   <chr>  <dbl>
#> 1 a          1
#> 2 a          2
#> 3 a          3
#> 4 b         78
#> 5 b         99

Created on 2021-09-07 by the reprex package (v2.0.0)

Hello claus,

your solution works pretty well, if there is one "non atomic" entry ("values" in this case). If there was another one I didn't manage to "loop" your idea.

Can you give an example of your issue? its hard to guess what you mean, I thought you meant

list.test <- list(
  list( id = "a", values = c(1, 2, 3) ,values2=c(4,5,6))
  , list( id = "b", values = c(78, 99) ,values2=c(101,102))
)

map_dfr(list.test, ~.)

but this works...

I hope this isn't to complicated but this script is the simplest I could do. The problem is, that i have a list, containing other lists, containing other lists, containg other lists, containing vectors.

#!/bin/env Rscript

suppressMessages(library("tidyverse"))

# A distinct analysis.
level3.list1 <- list(
    key1 = "name 1"
  , key2 = 14
  , key3 = 15
  , key4 = c(15, 29, 43, 57)
  , key5 = 332
  , key6 = c("A", "B", "C")
)

level3.list2 <- list(
    key1 = "name 2"
  , key2 = 28
  , key3 = 15
  , key4 = c(15, 43, 71, 99)
  , key5 = 332
  , key6 = c("Y", "Z")
)

level3.list3 <- list(
    key1 = "name 3"
  , key2 = 56
  , key3 = 22
  , key4 = c(78, 134, 190, 246)
  , key5 = 112
  , key6 = c("V")
)

# Grouped analyses.
level2.list1 <- list( level3.list1, level3.list2 )
level2.list2 <- list( level3.list3 )

# Planned samplings.
level1.list1 <- list(
    code = "ABC123"
  , type = "spot"
  , matrix = "water"
  , analyses = level2.list1
)

level1.list2 <- list(
    code = "GHS332"
  , type = "mix"
  , matrix = "water"
  , analyses = level2.list2
)

# All the samplings.
level0.list <- list(level1.list1, level1.list2)

# "Flattening".
map_dfr(level0.list, ~.)

# Gives at least:
# A tibble: 3 × 4
#  code   type  matrix analyses
#  <chr>  <chr> <chr>  <list>
#1 ABC123 spot  water  <named list [6]>
#2 ABC123 spot  water  <named list [6]>
#3 GHS332 mix   water  <named list [6]>

Is this understandable?

bit painful to figure out but it seems to work ...

tibble(level0.list) %>%
 unnest_wider(1) %>%
 unnest_longer(4) %>% 
unnest_wider(4) %>% 
unnest_longer(7) %>% 
unnest_longer(9)

Yes it does, thank you very much – this problem is haunting me since 2017.

I took a look at Hoist values out of list-columns — hoist • tidyr. But could you please elaborate on the integers a bit more?

the integers are just a quick way to select the columns to operate on, save me typing their names. but names are probably better for robust code over time. but if its a one off, id say numbers is fine.

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.