5

我正在处理三个存储在三个列表中的实验exp1exp2exp3。每个列表都有几个项目(nameconditionsdataset_adataset_b等)。有时我想对所有实验进行操作。有没有办法将它们的名称存储在变量中并动态调用它们?这不起作用:

all_exp <- list(exp1=exp1,exp2=exp2,exp3=exp3)

因为如果我以后在实验中添加一些东西,就会all_exp有以前状态下的实验的硬拷贝,而不是参考。

这类作品:

all_exp_names <- c("exp1","exp2","exp3")
all_exp <- lapply(all_exp_names, function(exp_name) (eval(parse(text=exp_name))))

但必须有更简单的方法,而且返回的列表会丢失实验名称。

4

2 回答 2

7

我想你想要

lapply(all_exp_names,get)

但这实际上并没有返回一个命名列表。你可以做

setNames(lapply(all_exp_names,get),all_exp_names)

诚然,这有点笨拙,尽管如果您经常使用它,您可以将它打包成一个函数(请参阅@JoshOBrien 的答案以获得更好的解决方案)。

我认为,更惯用的做法是首先将数据的参考副本保存在命名列表中。

编辑:我下面的原始延迟分配/评估代码很聪明,但完全忽略了 R 有一个内置delayedAssign函数的点,它与下面的函数做同样的事情(但可能更健壮)makeDelayVar

delayedAssign("exp_all",list(exp1=exp1,exp2=exp2))

(感谢do.call 和 curve 不能在另一个函数环境中绘制函数来指出这一点。)但是,%<%如下所示定义中缀运算符的技巧可能仍然很方便。


如果您真的想要延迟分配,这可行(但不简单):

makeActiveBinding("all_exp",function() list(exp1=exp1,exp2=exp2), .GlobalEnv)
exp1 <- 2
exp2 <- 3
all_exp
## $exp1
## [1] 2
##  
## $exp2
## [1] 3

您也可以将其包装在一个makeDelayVar函数中,尽管您可能必须小心评估环境。

makeDelayVar <- function(var,val) {
   makeActiveBinding(deparse(substitute(var)), function() val, parent.frame())
}
makeDelayVar(all_exp, list(exp1=exp1,exp2=exp2))
all_exp

这与上面的工作方式相同(如果您想确认此过程确实在进行延迟评估,您可以删除exp1and exp2、 define all_exp,然后重新定义)。exp[12]

为了更傻,你可以定义%<%做延迟赋值(R允许中缀运算符定义为%[character]%):

`%<%` <- makeDelayVar
all_exp %<% list(exp1,exp2)

I would use this with caution, though -- it could be fragile in some circumstances. For example, restrict it to interactive contexts where you will know right away if it breaks or does something funny, and don't try to be clever passing the results of delayed evaluation as arguments to functions etc.

于 2013-01-05T18:04:52.277 回答
7

If you want to keep the names, you could use sapply(..., simplify=FALSE, USE.NAMES=TRUE):

A <- B <- C <- 1:4
nms <- c("A", "B", "C")

sapply(nms, get, simplify=FALSE, USE.NAMES=TRUE)
## $A
## [1] 1 2 3 4
## 
## $B
## [1] 1 2 3 4
## 
## $C
## [1] 1 2 3 4
于 2013-01-05T19:10:19.480 回答