4

This question has a nice solution of flattening lists while preserving their data types (which unlist does not):

flatten = function(x, unlist.vectors=F) {
    while(any(vapply(x, is.list, logical(1)))) {
        if (! unlist.vectors)
            x = lapply(x, function(x) if(is.list(x)) x else list(x))
        x = unlist(x, recursive=F)
    }
    x
}

If I give it the following list, it behaves as expected:

> a = list(c(1,2,3), list(52, 561), "a")
> flatten(a)
[[1]]
[1] 1 2 3

[[2]]
[1] 52

[[3]]
[1] 561

[[4]]
[1] "a"

Now I'd like to restructure the flat list like a. relist fails miserably:

> relist(flatten(a), skeleton=a)
[[1]]
[[1]][[1]]
[1] 1 2 3

[[1]][[2]]
[1] 52

[[1]][[3]]
[1] 561

[[2]]
[[2]][[1]]
[[2]][[1]][[1]]
[1] "a"

[[2]][[2]]
[[2]][[2]][[1]]
NULL

[[3]]
[[3]][[1]]
NULL

Now, I could of course do relist(unlist(b), a) but that loses data types again. What is a good way to restructure a flat list?

Bonus points if it handles the analogous attribute to unlist.vectors correctly.

Community
  • 1
  • 1
Michael Schubert
  • 2,596
  • 4
  • 24
  • 44

1 Answers1

3

One way to do it is:

relist2 = function(x, like, relist.vectors=F) {
    if (! relist.vectors) 
        like = rapply(a, function(f) NA, how='replace')
    lapply(relist(x, skeleton=like), function(e) unlist(e, recursive=F))
}

This retains the classes and distinguishes between lists and vectors:

> relist2(flatten(a), like=a)
[[1]]
[1] 1 2 3

[[2]]
[[2]][[1]]
[1] 52

[[2]][[2]]
[1] 561

[[3]]
[1] "a"

> relist2(flatten(a, unlist.vectors=T), like=a, relist.vectors=T)
[[1]]
[1] 1 2 3

[[2]]
[[2]][[1]]
[1] 52

[[2]][[2]]
[1] 561

[[3]]
[1] "a"
Michael Schubert
  • 2,596
  • 4
  • 24
  • 44