2

Assume this simplified example:

L <- list()

L$Foo <- list()
L$Foo$Bar <- list()
L$Foo$Bar$VAR <- TRUE

L$Lorem <- list()
L$Lorem$Ipsum <- list()
L$Lorem$Ipsum$Dolor <- list()
L$Lorem$Ipsum$Dolor$VAR <- TRUE

I will then melt this list with reshape2::melt(L). That will output the following:

  value    L3    L2   L4    L1
1  TRUE   VAR   Bar <NA>   Foo
2  TRUE Dolor Ipsum  VAR Lorem

After some operations on certain cells in the value column, I'm then looking to recast this melted list into the exact same nested list structure as L—the only difference being that I updated a few of the value instances.

Any ideas how to achieve this? Please keep in mind that the nested lists can have any, and varying, depth.

markus
  • 25,843
  • 5
  • 39
  • 58
Christian
  • 932
  • 1
  • 7
  • 22
  • 2
    Is this an option: `tmp <- unlist(L); tmp[] <- FALSE; relist(tmp, L)` ? – markus Feb 17 '21 at 21:59
  • @markus Absolutely, this works well as long as I do my intended operations in a slightly different way than originally planned! Thank you! If you repost your comment as an answer, then I can accept it. – Christian Feb 17 '21 at 22:11

2 Answers2

2

An option is relist, after we unlisted L

tmp <- unlist(L)
# make small changes
tmp[] <- FALSE
relist(tmp, L)

Result

$Foo
$Foo$Bar
$Foo$Bar$VAR
[1] FALSE



$Lorem
$Lorem$Ipsum
$Lorem$Ipsum$Dolor
$Lorem$Ipsum$Dolor$VAR
[1] FALSE

L looks like

$Foo
$Foo$Bar
$Foo$Bar$VAR
[1] TRUE



$Lorem
$Lorem$Ipsum
$Lorem$Ipsum$Dolor
$Lorem$Ipsum$Dolor$VAR
[1] TRUE
markus
  • 25,843
  • 5
  • 39
  • 58
  • It looks like the updated list does not preserve the classes of the original structure. For instance, relisting gives `"TRUE"` (character class), not `TRUE` (logical class). Any thoughts on how to handle that? – Christian Feb 17 '21 at 22:42
  • Mmmmh, I get `logical`, when I run `class(relist(tmp, L)$Lorem$Ipsum$Dolor$VAR)`. Might be better to ask a separate question with reference to this one and new example data. – markus Feb 17 '21 at 22:46
  • Yes, the reason for that is my simplified example that didn't involve any character vectors. I posted a new question [here](https://stackoverflow.com/questions/66251237/relisting-a-flat-list-of-various-depth-preserving-classes) with a more elaborate example and details. – Christian Feb 17 '21 at 23:07
1

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
Joris C.
  • 5,721
  • 3
  • 12
  • 27