Building a tibble from a multi-level nested list?

60 Views Asked by At

I have a deeply nested list that I want to transform into a single tibble. At the top level there is some number of secondary lists. Each of these is the same length. Inside each of these is a tertiary list. Each of these contains a single value and an identifier.

What I want to do is make a tibble where the columns are named by the tertiary list identifiers, and the single values from each tertiary list are populated into that column as observations.

I have tried a lot of tweaks on something similar to this, but I'm just not that adept with these functions yet, and I'm not sure how to get this to work.

  # Convert to tibble
  temp <- map_dfr(lstTemp, ~tibble::tibble(!!pluck(., "identifiers") := pluck(., "values")))

Here's some code to generate a list structure like what I have.

set.seed(123)  # Setting seed for reproducibility

# Create a nested list structure
nested_list <- replicate(5, {
  lapply(1:14, function(counter) {
    list(
      identifiers = letters[counter],
      values = runif(1, 1, 10)
    )
  })
}, simplify = FALSE)
3

There are 3 best solutions below

2
Onyambu On BEST ANSWER

You could accomplish the same using the following:

library(jsonlite)   
library(tidyverse)

 map_df(fromJSON(toJSON(nested_list)), deframe)

# A tibble: 5 × 14
      a     b     c     d     e     f     g     h     i     j     k     l     m     n
  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1  3.59  8.09  4.68  8.95  9.46  1.41  5.75  9.03  5.96  5.11  9.61  5.08  7.10  6.15
2  1.93  9.10  3.21  1.38  3.95  9.59  9.01  7.24  6.76  9.95  6.90  7.38  5.90  6.35
3  3.60  2.32  9.67  9.12  7.22  8.16  1.22  5.30  7.83  2.95  3.86  3.08  2.29  4.73
4  4.72  4.32  2.37  2.25  3.10  5.19  3.39  8.72  1.41  4.98  8.19  2.10  6.05  2.86
5  2.15  7.78  9.06  4.37  6.99  1.85  4.46  3.47  8.33  5.04  8.29  8.31  8.15  4.96

map(nested_list, transpose) %>%
   array(length(.))%>%
   array2DF() %>%
   exec(pmap_df, ., ~set_names(unlist(..3), ..2))

# A tibble: 5 × 14
      a     b     c     d     e     f     g     h     i     j     k     l     m     n
  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1  3.59  8.09  4.68  8.95  9.46  1.41  5.75  9.03  5.96  5.11  9.61  5.08  7.10  6.15
2  1.93  9.10  3.21  1.38  3.95  9.59  9.01  7.24  6.76  9.95  6.90  7.38  5.90  6.35
3  3.60  2.32  9.67  9.12  7.22  8.16  1.22  5.30  7.83  2.95  3.86  3.08  2.29  4.73
4  4.72  4.32  2.37  2.25  3.10  5.19  3.39  8.72  1.41  4.98  8.19  2.10  6.05  2.86
5  2.15  7.78  9.06  4.37  6.99  1.85  4.46  3.47  8.33  5.04  8.29  8.31  8.15  4.96
1
r2evans On

There's nothing "pretty" here ...

library(dplyr)
bind_rows(
  lapply(nested_list, function(L1) 
    bind_cols(lapply(L1, function(L2) setNames(tibble(L2$values), L2$identifiers))))
)
# # A tibble: 5 × 14
#       a     b     c     d     e     f     g     h     i     j     k     l     m     n
#   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
# 1  3.59  8.09  4.68  8.95  9.46  1.41  5.75  9.03  5.96  5.11  9.61  5.08  7.10  6.15
# 2  1.93  9.10  3.21  1.38  3.95  9.59  9.01  7.24  6.76  9.95  6.90  7.38  5.90  6.35
# 3  3.60  2.32  9.67  9.12  7.22  8.16  1.22  5.30  7.83  2.95  3.86  3.08  2.29  4.73
# 4  4.72  4.32  2.37  2.25  3.10  5.19  3.39  8.72  1.41  4.98  8.19  2.10  6.05  2.86
# 5  2.15  7.78  9.06  4.37  6.99  1.85  4.46  3.47  8.33  5.04  8.29  8.31  8.15  4.96
0
CBRF23 On

After playing around and stepping through the examples provided, I came up with this, which gives me the same results. Certainly not going to win any code golf competitions but I find it more readable.

  temp <- lstTemp %>%
    map(transpose) %>%
    bind_rows() %>%
    unnest(everything()) %>%
    pivot_wider(names_from = identifiers, values_from = values, values_fn = list) %>%
    unnest(everything()) %>%
    rowwise() %>%
    mutate(Group = names(column)) %>%
    select(Group, everything())