Shorten recursive list

There are quite a few questions on this topic, but I don’t see any general solution: I have a very recursive list and you want to smooth it into one list of all the elements contained outside the lists.

For example, take this nested list:

d = list( list( list( iris[sample(1:150,3),], iris[sample(1:150,3),] ), list( list( iris[sample(1:150,3),], list( iris[sample(1:150,3),], iris[sample(1:150,3),] ) ) ) ) ) 

And include it in this:

 list(iris[sample(1:150,3),], iris[sample(1:150,3),], iris[sample(1:150,3),], iris[sample(1:150,3),], iris[sample(1:150,3),]) 

I have tried some of the following based on other solutions:

 purrr::flatten(d) plyr::llply(d, unlist) lapply(d, unlist, use.names=FALSE) 

There is no achievement of the desired result, which in the example is a single list length of 5, and all elements are data.frame . Any suggestions appreciated.

+8
r
source share
3 answers

This is a general smoothing function using only the base R:

 flatten <- function(x) { if (!inherits(x, "list")) return(list(x)) else return(unlist(c(lapply(x, flatten)), recursive = FALSE)) } 

Result:

 flatten(d) #[[1]] # Sepal.Length Sepal.Width Petal.Length Petal.Width Species #44 5.0 3.5 1.6 0.6 setosa #138 6.4 3.1 5.5 1.8 virginica #87 6.7 3.1 4.7 1.5 versicolor # #[[2]] # Sepal.Length Sepal.Width Petal.Length Petal.Width Species #19 5.7 3.8 1.7 0.3 setosa #1 5.1 3.5 1.4 0.2 setosa #71 5.9 3.2 4.8 1.8 versicolor # #[[3]] # Sepal.Length Sepal.Width Petal.Length Petal.Width Species #31 4.8 3.1 1.6 0.2 setosa #98 6.2 2.9 4.3 1.3 versicolor #134 6.3 2.8 5.1 1.5 virginica # #[[4]] # Sepal.Length Sepal.Width Petal.Length Petal.Width Species #140 6.9 3.1 5.4 2.1 virginica #119 7.7 2.6 6.9 2.3 virginica #57 6.3 3.3 4.7 1.6 versicolor # #[[5]] # Sepal.Length Sepal.Width Petal.Length Petal.Width Species #73 6.3 2.5 4.9 1.5 versicolor #54 5.5 2.3 4.0 1.3 versicolor #146 6.7 3.0 5.2 2.3 virginica 

Similarly:

 x <- list(list("A"), list(list("A"), list("A"))) flatten(x) #[[1]] #[1] "A" # #[[2]] #[1] "A" # #[[3]] #[1] "A" x <- list(list(1), list(list(2), list(3))) flatten(x) #[[1]] #[1] 1 # #[[2]] #[1] 2 # #[[3]] #[1] 3 

It seems a little cooler to add more lists when the goal is to delete them, but the list / unlist is the only reliable way to combine lists with a different number of elements.

+9
source share

Your data:

 d <- list( list( list( iris[sample(1:150,3),], iris[sample(1:150,3),] ), list( list( iris[sample(1:150,3),], list( iris[sample(1:150,3),], iris[sample(1:150,3),] ) ) ) ) ) 

First, a crude but effective function:

 f <- function(x) { if (is.null(x)) return n <- length(x) if (length(n) == 0) return for (i in 1:n) { if (is.data.frame(x[[i]])) { res <<- append(res, list(x[[i]])) } else { if (is.list(x[[i]])) { f(x[[i]]) } } } } 

A crude but effective companion global variable:

 res <- list() f(d) 

Results:

 res ## [[1]] ## Sepal.Length Sepal.Width Petal.Length Petal.Width Species ## 37 5.5 3.5 1.3 0.2 setosa ## 16 5.7 4.4 1.5 0.4 setosa ## 8 5.0 3.4 1.5 0.2 setosa ## ## [[2]] ## Sepal.Length Sepal.Width Petal.Length Petal.Width Species ## 10 4.9 3.1 1.5 0.1 setosa ## 141 6.7 3.1 5.6 2.4 virginica ## 86 6.0 3.4 4.5 1.6 versicolor ## ## [[3]] ## Sepal.Length Sepal.Width Petal.Length Petal.Width Species ## 134 6.3 2.8 5.1 1.5 virginica ## 40 5.1 3.4 1.5 0.2 setosa ## 3 4.7 3.2 1.3 0.2 setosa ## ## [[4]] ## Sepal.Length Sepal.Width Petal.Length Petal.Width Species ## 33 5.2 4.1 1.5 0.1 setosa ## 132 7.9 3.8 6.4 2.0 virginica ## 76 6.6 3.0 4.4 1.4 versicolor ## ## [[5]] ## Sepal.Length Sepal.Width Petal.Length Petal.Width Species ## 10 4.9 3.1 1.5 0.1 setosa ## 16 5.7 4.4 1.5 0.4 setosa ## 135 6.1 2.6 5.6 1.4 virginica 

Less crude (no global variable) solution:

 f2 <- function(x) { res <- list() if (is.null(x)) return n <- length(x) if (length(n) == 0) return for (i in 1:n) { if (is.data.frame(x[[i]])) { res <- append(res, list(x[[i]])) } else { if (is.list(x[[i]])) res <- append(res, f2(x[[i]])) } } return(res) } f2(d) ## same output 
+3
source share

rlang::squash pretty magical:

 set.seed(47) d = list(list(list(iris[sample(1:150,3),], iris[sample(1:150,3),]), list(list(iris[sample(1:150,3),], list(iris[sample(1:150,3),], iris[sample(1:150,3),]) )) )) rlang::squash(d) #> [[1]] #> Sepal.Length Sepal.Width Petal.Length Petal.Width Species #> 147 6.3 2.5 5.0 1.9 virginica #> 56 5.7 2.8 4.5 1.3 versicolor #> 113 6.8 3.0 5.5 2.1 virginica #> #> [[2]] #> Sepal.Length Sepal.Width Petal.Length Petal.Width Species #> 124 6.3 2.7 4.9 1.8 virginica #> 86 6.0 3.4 4.5 1.6 versicolor #> 103 7.1 3.0 5.9 2.1 virginica #> #> [[3]] #> Sepal.Length Sepal.Width Petal.Length Petal.Width Species #> 59 6.6 2.9 4.6 1.3 versicolor #> 70 5.6 2.5 3.9 1.1 versicolor #> 81 5.5 2.4 3.8 1.1 versicolor #> #> [[4]] #> Sepal.Length Sepal.Width Petal.Length Petal.Width Species #> 139 6.0 3.0 4.8 1.8 virginica #> 21 5.4 3.4 1.7 0.2 setosa #> 104 6.3 2.9 5.6 1.8 virginica #> #> [[5]] #> Sepal.Length Sepal.Width Petal.Length Petal.Width Species #> 25 4.8 3.4 1.9 0.2 setosa #> 90 5.5 2.5 4.0 1.3 versicolor #> 75 6.4 2.9 4.3 1.3 versicolor 
+3
source share

All Articles