2

I'd like to create a nested listed from a tibble, so the data is stored more efficiently and it is easier to extract information with subsetting.

I have a 3 column tibble like the following:

library(dplyr)

df <- tribble(
~a,~b,~c,
"a1", "b1", 1,
"a1", "b1", 2,
"a1", "b2", 1, 
"a1", "b2", 2,
)

I'd like to convert this to a list identical to this:

list(a1 = list(b1 = 1:2, b2 = 1:2))

Does anyone know how I can do this please?

Thanks

Sotos
  • 51,121
  • 6
  • 32
  • 66

3 Answers3

3

Split twice, i.e.

lapply(split(df,df$a), function(x) split(x$c,x$b))

$a1
$a1$b1
[1] 1 2

$a1$b2
[1] 1 2
Sotos
  • 51,121
  • 6
  • 32
  • 66
2

Something like the following?

library(tidyverse)

df <- tribble(
  ~a,~b,~c,
  "a1", "b1", 1,
  "a1", "b1", 2,
  "a1", "b2", 1, 
  "a1", "b2", 2,
)

df %>%
  group_by(a,b) %>% group_split() %>% map(~ list(.x$c) %>% set_names(.x$b[1])) %>% 
  unlist(recursive = F) %>% list %>% set_names(unique(df$a))

#> $a1
#> $a1$b1
#> [1] 1 2
#> 
#> $a1$b2
#> [1] 1 2
PaulS
  • 21,159
  • 2
  • 9
  • 26
1

rrapply() in the package rrapply has an option how = "unmelt" to convert melted data.frames into nested lists (which also works for arbitrary levels of nesting).

Each row in the input data.frame is converted to a single node path in the output nested list:

library(dplyr)
library(rrapply)

## 1 row -> 1 leaf
rrapply(df, how = "unmelt")
#> $a1
#> $a1$b1
#> [1] 1
#> 
#> $a1$b1
#> [1] 2
#> 
#> $a1$b2
#> [1] 1
#> 
#> $a1$b2
#> [1] 2

To assign multiple rows to a single leaf, we can nest the c column first:

## 2 rows -> 1 leaf
df %>% 
  group_by(a, b) %>%
  summarize(c = list(c), .groups = "drop") %>%
  rrapply(how = "unmelt")
#> $a1
#> $a1$b1
#> [1] 1 2
#> 
#> $a1$b2
#> [1] 1 2

Joris C.
  • 5,721
  • 3
  • 12
  • 27