4

I am looking for an efficient solution to (recursively) flatten a nested list (of arbitrary depth) into non-nested, 1 deep list. The list elements are not homogeneous, therefore they should not be unlisted into a vector (that would coerce all values to a single type). The best solution so far is:

flatlist <- function(mylist){
    lapply(rapply(mylist, enquote, how="unlist"), eval)
}

This does almost what I want:

> flatlist(list(foo=TRUE, bar=456, pets=list(cat="meeuw", dog="woof")))
$foo
[1] TRUE

$bar
[1] 456

$pets.cat
[1] "meeuw"

$pets.dog
[1] "woof"

However, a problem is that rapply is dropping NULL values, which is undesired:

> flatlist(list(foo=123, bar=NULL))
$foo
[1] 123

I would like that NULL elements appear in the output, either as NULL or as NA. Also the double loop with enquote and then eval makes things a bit slow. This function is used extensively in my code. Is there a way to do it all in one run?

Thomas
  • 40,508
  • 11
  • 98
  • 131
Jeroen
  • 28,942
  • 33
  • 116
  • 190
  • You could almost certainly adapt the code in [@Ferdinand.kraft's excellent answer to a similar question here](http://stackoverflow.com/questions/16679067/recursive-object-listing/16679358#16679358). In fact, looking at the comments there, it looks like you've already seen that answer! – Josh O'Brien Nov 01 '13 at 20:23
  • That solution is really inefficient, probably because of `result – Jeroen Nov 01 '13 at 21:38
  • Good to know. Thanks for the clarification. – Josh O'Brien Nov 01 '13 at 21:46
  • 1
    I would recommend checking [this thread](http://stackoverflow.com/questions/8139677/how-to-flatten-a-list-to-a-list-without-coercion) – Ramnath Nov 01 '13 at 23:39

1 Answers1

5

Replace the rapply part by your own recursion so NULLs are not getting any special treatment:

renquote <- function(l) if (is.list(l)) lapply(l, renquote) else enquote(l)

lapply(unlist(renquote(ml)), eval)
flodel
  • 82,429
  • 18
  • 167
  • 205