An alternative could be to use rrapply()
in the rrapply
-package which has options how = "melt"
and how = "unmelt"
to transform between nested lists and melted data.frames:
library(rrapply)
L <- list(Foo = list(Bar = list(VAR = TRUE)), Lorem = list(Ipsum = list(Dolor = list(VAR = TRUE))))
## melt to data.frame
(L1 <- rrapply(L, how = "melt"))
#> L1 L2 L3 L4 value
#> 1 Foo Bar VAR <NA> TRUE
#> 2 Lorem Ipsum Dolor VAR TRUE
## cast back to nested list
L2 <- rrapply(L1, how = "unmelt")
str(L2)
#> List of 2
#> $ Foo :List of 1
#> ..$ Bar:List of 1
#> .. ..$ VAR: logi TRUE
#> $ Lorem:List of 1
#> ..$ Ipsum:List of 1
#> .. ..$ Dolor:List of 1
#> .. .. ..$ VAR: logi TRUE
identical(L2, L)
#> [1] TRUE
An important advantage with respect to relist()
is that no list skeleton object is needed (see ?relist
), so we are not constrained by the list format defined in the skeleton object when modifying the melted data.frame, e.g.:
L_unlist <- unlist(as.relistable(L))
## this change has no effect when relisting
## as the original list is used as skeleton
names(L_unlist)[1] <- "Foo.Bar.Test"
relist(L_unlist)
#> $Foo
#> $Foo$Bar
#> $Foo$Bar$VAR
#> [1] TRUE
#>
#> $Lorem
#> $Lorem$Ipsum
#> $Lorem$Ipsum$Dolor
#> $Lorem$Ipsum$Dolor$VAR
#> [1] TRUE
#>
#> attr(,"class")
#> [1] "relistable" "list"
## here it does behave as expected
L_melt <- rrapply(L, how = "melt")
L_melt[1, "L3"] <- "Test"
rrapply(L_melt, how = "unmelt")
#> $Foo
#> $Foo$Bar
#> $Foo$Bar$Test
#> [1] TRUE
#>
#> $Lorem
#> $Lorem$Ipsum
#> $Lorem$Ipsum$Dolor
#> $Lorem$Ipsum$Dolor$VAR
#> [1] TRUE