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

时间:2018-03-15 17:59:08

标签: r

我在R中有一个列表:

my_list <- list(a = 1, b = 2, c = list(d = 4, e = 5))

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

  1. 列出该元素的子集,但不知道包含它的主列表的结构
  2. 了解其父列表的名称(即元素c
  3. 是否有一个简单的方法/包可以解决这个看似简单的问题?

3 个答案:

答案 0 :(得分:4)

我正在实施@ r2evans的建议。我确信这可以改进:

getParentChild <- function(lst, myN) {
    myFun <- function(lst, myN) {
        test <- which(names(lst) == myN)
        if (length(test) > 0)
            return(lst[test])

        lapply(lst, function(x) {
            if (is.list(x))
                myFun(x, myN)
        })
    }

    temp <- myFun(lst, myN)
    temp[!sapply(temp, function(x) is.null(unlist(x)))]
}

getParentChild(my_list, "d")
$c
$c$d
[1] 4

这是一个更复杂的例子,说明当有多个子女/孙子女时,getParentChild如何显示血统。

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)

getParentChild(exotic_list, "n")
$l
$l$n
$l$n$o
[1] 7

$l$n$p
[1] 8

答案 1 :(得分:2)

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

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
}

示例问题:

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

@ 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

<小时/> 使用purrr package我们也可以摆脱vapply s,制作 功能稍微简洁一点,也许更具可读性:

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

reprex package(v0.2.0)创建于2018-03-15。

答案 2 :(得分:1)

也许以下内容会做你想要的。

wanted <- "d"

inx <- grep(wanted, names(unlist(my_list)), value = TRUE)
unlist(my_list)[inx]
#c.d 
#  4

sub(paste0("(\\w)\\.", wanted), "\\1", inx)
#[1] "c"