展平递归列表

时间:2017-12-02 01:11:04

标签: r

显然有很多关于这个主题的问题,但我看不出任何一般的解决方案:我有一个深度递归的列表,并希望将其展平为包含所有非列表项的单个列表

例如,请使用此嵌套列表:

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),]
        )
      )
    )
  )
)

把它变成这个:

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),])

我根据其他解决方案尝试了以下一些方法:

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

无达到期望的结果,在该示例中是单个列表长度5,所有项目都是data.frame。任何建议表示赞赏。

4 个答案:

答案 0 :(得分:9)

这是仅使用基数R的一般展平函数:

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

结果:

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

类似地:

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

当目标是删除更多列表时,似乎有点过时了,但list / unlist路由是连接具有不同数量元素的列表的唯一可靠方法。

答案 1 :(得分:5)

rlang::squash非常神奇:

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

答案 2 :(得分:3)

您的数据:

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),]
        )
      )
    )
  )
)

首先,一个粗略但有效的功能:

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]])
      }
    }

  }

}

粗略但有效的伴随全局变量:

res <- list()

f(d)

结果:

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

较少原油(无全局变量)解决方案:

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 :(得分:1)

rrapply包中的

rrapplyrapply的概括,可以将嵌套列表展平为叶子列表。 dfaslist=FALSE将导致数据帧被视为叶子,而不是被递归到其中。

library(rrapply)

rrapply(d, f = identity, dfaslist = FALSE, how = "flatten")