在不知道r中的结构的情况下设置列表

Jac*_*son 6 r

我在R中有一个列表:

my_list <- list(a = 1, b = 2, c = list(d = 4, e = 5))
Run Code Online (Sandbox Code Playgroud)

假设我不知道列表的结构,但我知道在这个列表的某个地方,有一个名为d嵌套或不嵌套的元素.我想要:

  1. 列表元素的子集,不知道包含它的主列表的结构
  2. 知道其父列表的名称(即元素c)

是否有一个简单的方法/包可以解决这个看似简单的问题?

Mik*_*ila 2

这是另一种递归方法,与 @JosephWood 的答案非常相似,它概括了解决方案,以便您可以同时搜索多个元素,并找到所有匹配元素(如果有多个):

find_all <- function(x, elements) {
  lists <- vapply(x, is.list, logical(1)) # find sublists

  # find all elements in sublists
  out <- lapply(x[lists], find_all, elements)
  out <- out[!vapply(out, is.null, logical(1))]

  # output any found elements
  if (any(elements %in% names(x)))
    out <- c(out, x[names(x) %in% elements])

  if (length(out) == 0) NULL else out
}
Run Code Online (Sandbox Code Playgroud)

示例问题:

my_list <- list(a = 1, b = 2, c = list(d = 4, e = 5))
str(find_all(my_list, "e"))
#> List of 1
#>  $ c:List of 1
#>   ..$ e: num 5
Run Code Online (Sandbox Code Playgroud)

@JosephWood 的奇异例子更加复杂:

exotic_list <-
  list(
    a = 1,
    b = 2,
    c = list(d = 4, e = 5),
    f = list(g = 6, h = list(k = 7, j = 8)),
    l = list(m = 6, n = list(o = 7, p = 8)),
    q = list(r = 5, s = 11),
    t = 12,
    n = 13
  )

str(find_all(exotic_list, c("n", "q")))
#> List of 3
#>  $ l:List of 1
#>   ..$ n:List of 2
#>   .. ..$ o: num 7
#>   .. ..$ p: num 8
#>  $ q:List of 2
#>   ..$ r: num 5
#>   ..$ s: num 11
#>  $ n: num 13
Run Code Online (Sandbox Code Playgroud)


使用该purrr包,我们还可以去掉vapplys,使函数更加简洁,也许也更具可读性:

library(purrr)

find_all2 <- function(x, elements) {
  # find all elements in sublists
  out <- map(keep(x, is.list), find_all, elements)
  out <- compact(out) # drop nulls

  # output any found elements
  if (any(elements %in% names(x)))
    out <- c(out, x[names(x) %in% elements])

  if (length(out) == 0) NULL else out
}

identical(
  find_all(exotic_list, c("n", "q")),
  find_all2(exotic_list, c("n", "q"))
)
#> [1] TRUE
Run Code Online (Sandbox Code Playgroud)

由reprex 包(v0.2.0)于 2018 年 3 月 15 日创建。