首页 > 解决方案 > 如何使用变量名创建未知深度列表?

问题描述

我想创建一个未知深度的列表。

这在某种程度上与我的另一个问题有关(将函数应用于参数网格并返回 purrr 中的列表列表),但我认为这可能值得自己发表。

在犯了一些错误之后,我发现可以通过编写以下代码来创建这样的列表:

rtn = list()
rtn$a$f$t=6
rtn

这给出了深度 4 的列表(根据purrr:vec_depth(rtn)),这正是预期的输出。

$a
$a$f
$a$f$t
[1] 6

不幸的是,当我尝试使用名称时,rtn[["a"]][["f"]][["t"]]="6"没有用:

$a
  f 
"6"

这里,rtn是一个简单向量的列表rtn$a,并且“t”索引被删除。

阅读时,我注意到有一章关于“递归(类列表)对象”,其中说明了和?Extract之间的区别:[[<-$<-

$<-应用于 aNULL x时,它首先强制x转换为list()[[<-如果替换值value的长度大于 1 ,也会发生这种情况:如果value长度为 1 或 0,x则首先将其强制为值类型的零长度向量。

我怎么能用变量构造这样一个列表?(最好使用 base R 或任何tidyverse/rlang包)

到目前为止,这是我的尝试:

免责声明:这可能是我写过的最丑陋的代码之一,这个操作符重新分配(这并不完全有效),但谁知道呢,它可能会带来更好的东西......

`[[<-`=`$<-` #yuck...
rtn = list()
rtn$a$f$t=6
rtn[["a"]][["f"]][["t"]]="6" #this works!
xx="b"
rtn[[xx]][["f"]][["t"]]="6" #but this does not: unexpectedly it creates a level "xx" instead of "b"
rm(`[[<-`) #better safe than sorry
rtn

标签: rlist

解决方案


解决此类问题的一种直接方法是使用递归函数。一种方法是(完全编辑的原始帖子):

ff = function(nms, val, init = list())
{
  if(!length(nms)) return(val)
  init[[nms[1]]] = c(init[[nms[1]]], ff(nms[-1], val))
  return(init)
}

在更新现有列表时对其进行测试:

rtn = list()
rtn$a$f$t = 6
rtn$a$j$r = 19
rtn$b$r = 3
rtn$b$v$f$w = 42
rtn$c$e = 11

rtn2 = ff(c("a", "f", "t"), 6)
rtn2 = ff(c("a", "j", "r"), 19, rtn2)
rtn2 = ff(c("b", "r"), 3, rtn2)
rtn2 = ff(c("b", "v", "f", "w"), 42, rtn2)
rtn2 = ff(c("c", "e"), 11, rtn2)

identical(rtn, rtn2)
#[1] TRUE

推荐阅读