Recursively apply a function to list items

Using the rmatio package , I get nested lists similar to the following:

nestedlist <- list(
    a = list( a = list(1:10), b = list(35)),
    b = list(11:25)
)

Ideally, I want it to look like this (all lists with one unnamed element replaced by an element):

nestedlist <- list(a = list(a=1:10, b=35), b = 11:25)

I tried already tried the following:

unlist(nestedlist) # returns one vector with all elements

selective_unlist <- function(e)
    if(is.list(e) &&is.null(names(e))) unlist(e) else e

# only calls the function with each leaf, so nothing gets replaced
rapply(nestedlist, how='replace', selective_unlist)

# works, but only for 2 levels
lapply(nestedlist, selective_unlist)

# works, but using explicit recursion is slow for large datasets
recursive_selective_unlist <- function(e)
    if(is.list(e)) {
        if(is.null(names(e))) unlist(e)
        else lapply(e, recursive_selective_unlist)
    }   else e

Is there a better / faster way to simplify these nested lists or is it the most recursive function?

+4
source share
2 answers

Following @Pafnucy's idea, I would use

ff <- function(x) if (is.list(x[[1]])) lapply(x,ff) else unlist(x)

which makes

ff(nestedlist)
# $a
# $a$a
#  [1]  1  2  3  4  5  6  7  8  9 10
# 
# $a$b
# [1] 35
# 
# 
# $b
#  [1] 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
# check result:
identical(list(a = list(a=1:10, b=35), b = 11:25),ff(nestedlist))
# [1] TRUE
+3
source

Processing arbitrary depth of nesting:

f <- function(x) {
    if (is.list(x)) unname(c(sapply(unlist(x), f))) else x
}

# sample data
nl2 <- list(a = list(a = list(1:5), b = list(1:5)))
nl3 <- list(p = nl2, q = c(9,9,9))

Intermediate output:

> f(nl2)
 [1] 1 2 3 4 5 1 2 3 4 5
> f(nl3)
 [1] 1 2 3 4 5 1 2 3 4 5 9 9 9

Adding the last step as it fgoes too deep and we need a list with depth 1

unstackList <- function(x) lapply(x, f)
unstackList(nl3)

Conclusion:

$p
 [1] 1 2 3 4 5 1 2 3 4 5

$q
[1] 9 9 9
+2
source

All Articles