【问题标题】:Extracting Information from Multi-Level Nested Lists从多级嵌套列表中提取信息
【发布时间】:2018-06-23 09:01:33
【问题描述】:

我在一个嵌套列表中有一组数据,这样顶部列表的每个成员都有描述符(但不一定是相同的描述符),然后是一个子列表,这些孩子可以有孩子,依此类推.孩子的深度是任意的。一个小例子:

family <- list(
  list(name = "Alice", age = 40, eyes = "blue", children = list(
    list(name = "Bob", age = 20, eyes = "blue"),
    list(name = "Charlie", age = 18, eyes = "brown")
)), 
  list(name = "Dan", age = 12, eyes = "green"),
  list(name = "Erin", age = 69, eyes = "green", children = list(
    list(name = "Frank", age = 45, eyes = "blue", children = list(
      list(name = "George", age = 24, eyes = "blue", children = list(
        list(name = "Harry", age = 2, eyes = "green")
      )), 

      list(name = "Ingrid", age = 22, eyes = "brown", hair = "brown"),
      list(name = "Jack", age = 29, eyes = "brown")
    )), 
    list(name = "Karen", age = 43),
    list(name = "Larry", age = 21, eyes = "blue")
  )) 
)

> str(family, max.level = 2)
List of 3
 $ :List of 4
  ..$ name    : chr "Alice"
  ..$ age     : num 40
  ..$ eyes    : chr "blue"
  ..$ children:List of 2
 $ :List of 3
  ..$ name: chr "Dan"
  ..$ age : num 12
  ..$ eyes: chr "green"
 $ :List of 4
  ..$ name    : chr "Erin"
  ..$ age     : num 69
  ..$ eyes    : chr "green"
  ..$ children:List of 3

理想情况下,我想创建一个数据框,使每一行都是一个家庭成员,每一列都是列表中的一个属性:

      name       age      eyes
    1 Alice       40      blue
    2 Bob         20      blue
    3 Charlie     18      brown
(etc)

但目前还不清楚如何递归到任意深度。我已经设法使用map(family, ~ .$name) 获得顶级成员,但我不明白如何更深入。一些成员没有孩子这一事实使情况变得复杂。

我已经查看了 purrr 文档,但我找不到任何看起来有帮助的东西。也许我没有使用正确的术语。

不胜感激。谢谢!

【问题讨论】:

    标签: r tidyverse purrr


    【解决方案1】:

    您始终可以递归地遍历列表并收集信息。除了来自purrr 的map_dfr 之外,我的解决方案还使用来自plyr 的defaults 来处理缺少眼睛或头发颜色的情况。

    get_people <- function(x) {
      if (is.null(x)) return(NULL)
      if (!is.null(x$name)) { # if there's a name, we're at the level of a person
        children <- x$children
        x$children <- NULL
        row <- data.frame(plyr::defaults(x, list(age = NA, eyes = NA, hair = NA)),
                          stringsAsFactors = FALSE)
        rbind(row, get_people(children))
      }
      else {
        purrr::map_dfr(x, get_people)
      }
    }
    

    当您将此应用于您的列表时:

    > get_people(family)
          name age  eyes  hair
    1    Alice  40  blue  <NA>
    2      Bob  20  blue  <NA>
    3  Charlie  18 brown  <NA>
    4      Dan  12 green  <NA>
    5     Erin  69 green  <NA>
    6    Frank  45  blue  <NA>
    7   George  24  blue  <NA>
    8    Harry   2 green  <NA>
    9   Ingrid  22 brown brown
    10    Jack  29 brown  <NA>
    11   Karen  43  <NA>  <NA>
    12   Larry  21  blue  <NA>
    

    【讨论】:

      【解决方案2】:

      这是一个迭代 children 元素的选项,将人员收集到一个扁平列表中:

      flatten_family <- function(x){
          ppl <- list()
      
          rflatten <- function(y){
              lapply(y, function(z){
                  if(exists('children', z)) {
                      ppl <<- c(ppl, list(z[-which(names(z) == 'children')]))
                      rflatten(z$children)
                  } else {
                      ppl <<- c(ppl, list(z))
                  }
              })
              ppl
          }
      
          rflatten(x)
      }
      
      dplyr::bind_rows(flatten_family(family))
      #> # A tibble: 12 x 4
      #>    name      age eyes  hair 
      #>    <chr>   <dbl> <chr> <chr>
      #>  1 Alice   40.0  blue  <NA> 
      #>  2 Bob     20.0  blue  <NA> 
      #>  3 Charlie 18.0  brown <NA> 
      #>  4 Dan     12.0  green <NA> 
      #>  5 Erin    69.0  green <NA> 
      #>  6 Frank   45.0  blue  <NA> 
      #>  7 George  24.0  blue  <NA> 
      #>  8 Harry    2.00 green <NA> 
      #>  9 Ingrid  22.0  brown brown
      #> 10 Jack    29.0  brown <NA> 
      #> 11 Karen   43.0  <NA>  <NA> 
      #> 12 Larry   21.0  blue  <NA>
      

      【讨论】:

        猜你喜欢
        • 2021-05-23
        • 1970-01-01
        • 1970-01-01
        • 2021-11-05
        • 2015-05-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-05
        相关资源
        最近更新 更多