我在R中有一个列表:
my_list <- list(a = 1, b = 2, c = list(d = 4, e = 5))
假设我不知道列表的结构,但我知道在这个列表的某个地方,有一个名为d
的元素,嵌套与否。我想:
c
)是否有一个简单的方法/包可以解决这个看似简单的问题?
答案 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"