对于命名的嵌套列表,提取特定元素的最佳方法是什么?如果我有一个包含已知字段的列表(例如,来自yaml文件),我想提取一个元素(列表或其他),而不必搜索名称和索引或试图跟踪{{1中的级别输出。
例如,我知道str
会返回包含lm
信息的嵌套列表。
qr
但如果我不知道顺序,我只想指定列表以及元素的名称。理想情况下,某些东西会给我元素的和元素的索引路径和元素本身。
答案 0 :(得分:3)
我的递归版本1开始变得比我初想的更多,所以我采取了一个简单的方法,基本上是在抓取fit <- lm(mpg ~ wt, mtcars)
fit$qr$qraux
# [1] 1.176777 1.046354
的捕获输出(我认为)。
到目前为止,这至少有两个缺点:捕获输出和eval-parse-texting,但它似乎适用于非常嵌套的列表,例如utils:::print.ls_str
。
这些只是一些辅助功能
ggplot2::ggplotGrob
这一个正在返回有用的信息
unname2 <- function(l) {
## unname all lists
## str(unname2(lm(mpg ~ wt, mtcars)))
l <- unname(l)
if (inherits(l, 'list'))
for (ii in seq_along(l))
l[[ii]] <- Recall(l[[ii]])
l
}
lnames <- function(l) {
## extract all list names
## lnames(lm(mpg ~ wt, mtcars))
nn <- lpath(l, TRUE)
gsub('\\[.*', '', sapply(strsplit(nn, '\\$'), tail, 1))
}
lpath <- function(l, use.names = TRUE) {
## return all list elements with path as character string
## l <- lm(mpg ~ wt, mtcars); lpath(l); lpath(l, FALSE)
ln <- deparse(substitute(l))
# class(l) <- NULL
l <- rapply(l, unclass, how = 'list')
L <- capture.output(if (use.names) l else unname2(l))
L <- L[grep('^\\$|^[[]{2,}', L)]
paste0(ln, L)
}
所以我可以直接使用该返回值,或者现在我有索引。
lextract <- function(l, what, path.only = FALSE) {
# stopifnot(what %in% lnames(l))
ln1 <- eval(substitute(lpath(.l, TRUE), list(.l = substitute(l))))
ln2 <- eval(substitute(lpath(.l, FALSE), list(.l = substitute(l))))
cat(ln1[idx <- grep(what, ln1)], sep = '\n')
cat('\n')
cat(ln2[idx], sep = '\n')
cat('\n')
if (!path.only)
setNames(lapply(idx, function(x) eval(parse(text = ln1[x]))), ln1[idx])
else invisible()
}
fit <- lm(mpg ~ wt, mtcars)
lextract(fit, 'qraux')
# fit$qr$qraux
#
# fit[[7]][[2]]
#
# [1] 1.176777 1.046354
然而,我更喜欢内置或单行。
答案 1 :(得分:2)
这是另一种递归尝试。我不确定输出应该如何构建,但我认为这提供了足够的信息来提取其余部分。
这里的返回值是索引的向量和元素的长度。因此,对于fit
示例,它返回c(inds=7, len=5)
,对应于fit
中的第7个位置,并且元素的长度为5。
rnames <- function(lst, item) {
f <- function(ll, inds) {
if ((ii <- match(item, names(ll), FALSE)))
list(inds=c(inds, ii), len=length(ll[[ii]]))
else if (all(is.atomic(unlist(ll, FALSE))) || !is.list(ll))
NULL
else
lapply(seq_along(ll), function(i) f(ll[[i]], inds=c(inds, i)))
}
unlist(f(lst, NULL))
}
rnames(fit, "qr")
# inds len
# 7 5
这只会找到第一个匹配项,因此如果列表中有多个具有相同名称的元素,它将返回第一个匹配项的索引。一个稍微嵌套的例子,其中只有第一个&#34; d&#34;将被退回。
lst <- list(
"a"=list("b"=1, "c"=2, "d"=list(1:5)),
"d"=list("f"=5),
"g"=list("h"=list("i"=1:5), "k"=list(1:3, list(letters[1:4])))
)
rnames(lst, "d")
# inds len
# 2 1
并且,当有多层嵌套时
rnames(lst, "k")
# inds1 inds2 len
# 3 2 2
## So, that would correspond to
lst[[3]][[2]][1:2]