6

I would like to convert nested list like this:

l <- list(A=list(a=list(1),b=list(2)),
          B=list(cd=list(c=list(3,4,5),d=list(6,7,8)),e=list(c(9,10))))

into list

o <- list(A=c(1,2),A.a=1,A.b=2,B=c(3:10),
          B.cd=c(3:8),B.cd.c=c(3:5),B.cd.d=c(6:8),B.e=c(9:10))

At each list level values from nested lists should be concatenated.

Wojciech Sobala
  • 7,431
  • 2
  • 21
  • 27
  • I think you can get something like this with some combination of lapply and rapply, but I've yet to find the magic combination. – Ista Mar 09 '11 at 17:48

1 Answers1

7

Clearly a case for a recursive function, but getting the return values to unlist properly is tricky. Here's a function that will do it; it doesn't get the names quite right but that's easily fixed afterwards.

unnest <- function(x) {
  if(is.null(names(x))) {
    list(unname(unlist(x)))
  }
  else {
    c(list(all=unname(unlist(x))), do.call(c, lapply(x, unnest)))
  }
}

Output from unnest(l) is

$all
 [1]  1  2  3  4  5  6  7  8  9 10

$A.all
[1] 1 2

$A.a
[1] 1

$A.b
[1] 2

$B.all
[1]  3  4  5  6  7  8  9 10

$B.cd.all
[1] 3 4 5 6 7 8

$B.cd.c
[1] 3 4 5

$B.cd.d
[1] 6 7 8

$B.e
[1]  9 10

and can be massaged into your desired output with

out <- unnest(l)
names(out) <- sub("\\.*all", "", names(out))
out[-1]

To not recurse when there's only one element, try

unnest2 <- function(x) {
  if(is.null(names(x)) | length(x)==1) {
    list(unname(unlist(x)))
  } else {
    c(list(all=unname(unlist(x))), do.call(c, lapply(x, unnest2)))
  }
}
Aaron left Stack Overflow
  • 36,704
  • 7
  • 77
  • 142
  • @Aaron it works almost as I expected with only one exception for list list(C=list(f=list(11))) it gives result list(all=11,C.all=11, C.f=11). – Wojciech Sobala Mar 09 '11 at 21:23
  • @Wojciech: Hm. That's what I'd expect; there are three levels of nesting (counting the highest level), so there are three items in the output list. What did you expect instead? – Aaron left Stack Overflow Mar 09 '11 at 21:52
  • @Aaron in such cases I would expect only results from highest level of list. I can remove repeated vectors from output of unnest function, but I wonder if it is possible to modify this function. – Wojciech Sobala Mar 10 '11 at 08:18
  • Ok it should work in this case but maybe in more general case it would be better to change length(x) to length(unlist(x)). Thanks. – Wojciech Sobala Mar 10 '11 at 19:48
  • Except that `length(unlist(x))` won't be equal to one if what's inside the nesting is a vector of length greater than one. Try it with `c(11,12)` instead of `11` in your example. – Aaron left Stack Overflow Mar 11 '11 at 04:16