从多级嵌套列表中提取信息

CDo*_*oug 4 r purrr tidyverse

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

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
Run Code Online (Sandbox Code Playgroud)

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

      name       age      eyes
    1 Alice       40      blue
    2 Bob         20      blue
    3 Charlie     18      brown
(etc)
Run Code Online (Sandbox Code Playgroud)

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

我已经阅读了purrr文档,但我找不到任何看起来会有所帮助的内容.也许我没有使用正确的术语.

建议表示赞赏.谢谢!

Cla*_*lke 7

您始终可以递归地遍历列表并收集信息.除了map_dfrpurrr我的解决方案采用defaultsplyr处理缺失眼睛或头发的颜色的情况下.

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)
  }
}
Run Code Online (Sandbox Code Playgroud)

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

> 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>
Run Code Online (Sandbox Code Playgroud)