Flatten recursive list

前端 未结 4 1186
无人共我
无人共我 2021-02-14 09:33

There are quite a few questions apparently on this topic, but I can\'t see any general solution proposed: I have a deeply recursive list and want to flatten it into a single lis

相关标签:
4条回答
  • 2021-02-14 09:40

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

    The crude but effective accompanying global variable:

    res <- list()
    
    f(d)
    

    The 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
    
    0 讨论(0)
  • 2021-02-14 09:45

    This is a general flatten function using only 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 bit round-about to add more lists when the goal is to remove them, but the list/unlist route is the only reliable way to concatenate lists with different numbers of elements.

    0 讨论(0)
  • 2021-02-14 09:57

    rrapply in the rrapply package is a generalization of rapply that can flatten the nested list into a list of leaves. dfaslist=FALSE will cause data frames to be regarded as leaves rather than being recursed into.

    library(rrapply)
    
    rrapply(d, f = identity, dfaslist = FALSE, how = "flatten")
    
    0 讨论(0)
  • 2021-02-14 10:05

    rlang::squash is 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
    
    0 讨论(0)
提交回复
热议问题