R 从嵌套列表中按名称提取元素

R 从嵌套列表中按名称提取元素,r,list,nested-lists,R,List,Nested Lists,对于命名的嵌套列表,提取特定元素的最佳方法是什么?如果我有一个包含已知字段的列表(例如,来自yaml文件),我希望提取一个元素(列表或其他),而不必搜索名称和索引,也不必跟踪str输出中的级别 例如,我知道lm返回一个嵌套列表,其中包含qrinfo fit <- lm(mpg ~ wt, mtcars) fit$qr$qraux # [1] 1.176777 1.046354 fit我的递归版本1开始出现比我最初想象的更多的错误,因此我采取了一种简单的方法,基本上将捕获的utils:::

对于命名的嵌套列表,提取特定元素的最佳方法是什么?如果我有一个包含已知字段的列表(例如,来自yaml文件),我希望提取一个元素(列表或其他),而不必搜索名称和索引,也不必跟踪
str
输出中的级别

例如,我知道
lm
返回一个嵌套列表,其中包含
qr
info

fit <- lm(mpg ~ wt, mtcars)
fit$qr$qraux
# [1] 1.176777 1.046354

fit我的递归版本1开始出现比我最初想象的更多的错误,因此我采取了一种简单的方法,基本上将捕获的
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)
}

不过,我更喜欢内置的或单行程序。

这里是另一个递归尝试。我不确定输出应该如何构造,但我认为这提供了足够的信息来提取其余部分

这里的返回值是索引向量和元素长度。因此,对于
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 

请参阅
purrr
package。它就是为这个而做的。对于线性模型,您还可以查看
broom
package。你会喜欢的。另一个相关问题:
fit[[7]][[2]]
# [1] 1.176777 1.046354


## etc
lextract(fit, 'qr', TRUE)

# fit$qr
# fit$qr$qr
# fit$qr$qraux
# fit$qr$pivot
# fit$qr$tol
# fit$qr$rank
# 
# fit[[7]]
# fit[[7]][[1]]
# fit[[7]][[2]]
# fit[[7]][[3]]
# fit[[7]][[4]]
# 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 
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]