我正在尝试为循环中的每个元素分配一个函数。 我希望函数使用变量的值,但它们使用变量的最后一个值:
assign.instrumentslist = function()
{
for(instList in lists.instruments)
{
assign(
paste("test", instList, sep="."),
function() {print(instList)},
envir = .GlobalEnv
)
}
}
lists.instruments = c("CL", "HO", "GC")
assign.instrumentslist()
test.CL()
# return "GC"
THX
答案 0 :(得分:4)
这可能是最简单的方法:
assign.instrumentslist = function() {
for(instList in lists.instruments) {
local({
i <- instList
assign(
paste("test", instList, sep="."),
function() {print(i)},
pos = .GlobalEnv
)
})
}
}
关键是在函数的封闭环境中创建本地对象(i
)。
在此示例中,环境由local
生成。
这真是一个非常糟糕的黑客:
lapply(lists.instruments,
function(x) .GlobalEnv[[paste("test1", x, sep=".")]] <- function() print(x))
答案 1 :(得分:2)
使用参数有什么问题?
AsItShouldBeDone <-
function(x){
print(x)
}
> AsItShouldBeDone('CL')
[1] "CL"
这与打字工作差不多:将CL作为参数而不是对函数名称的额外添加。这就是你应该怎么做的。
您的解决方案有什么问题? :
assign()
的使用:用任何语言在函数中改变你的全局环境是非常不明智的,而且绝对完全违背了R的思维方式。所以不要。我碰巧在我的工作区中有一个名为test.CL的数据框。嗯,现在已经不见了...... 使用不同的名称创建不同的函数,并且所有函数都使用相同的代码。这是为什么?如果您正在尝试查找为不同类分配S3方法的快捷方式,请尝试以下操作。在任何其他情况下,使用参数使您的函数执行它应该的操作
test.CL <- test.HO <- test.GC <- function(x) print(x)
期望变量的值在循环内的函数中进行硬编码。不,这不对。 R告诉你这是函数:
> test.CL
function() {print(instList)}
<environment: 0x05e32224>
所以它的作用非常明显:它从环境中给出的环境中打印出instList。这是您的第一个功能创建的环境。其中包含循环后的instList的值。这是最后一个值。
这种机制被Koshke的方法攻击了。有用。这不是因为它应该使用它,相反;像这样的黑客环境可能会产生非常有趣的副作用,并且绝不是稳定的代码。另外,如前所述:
为基督的使用辩护!
答案 2 :(得分:2)
我可以解释一下这种行为,但不确定解决问题的正确方法是什么(环境会让我受伤)。
问题是您的匿名功能会选择一个环境。它是寻找对象的环境,包括instList
。在第一次迭代中,它获取此环境<environment: 0x28e19a8>
,这是正在评估的函数的当前环境(assign.instrumentslist()
):
Browse[2]> environment()
<environment: 0x28e19a8>
在循环的下一次迭代中,当前环境instList
中<environment: 0x28e19a8>
的值变为"HO"
。现在,test.CL()
和test.HO()
都具有相同的环境,因此请引用相同的instList
,其现在具有值"HO"
。同样的事情发生在test.GC()
的最后一次迭代中。以下调试脚本显示了这一点:
debug at #5: assign(paste("test", instList, sep = "."), function() {
print(instList)
}, envir = .GlobalEnv)
Browse[2]>
debug at #3: instList
Browse[2]> environment(test.CL)
<environment: 0x28e19a8>
Browse[2]> eval(instList, environment(test.CL))
[1] "CL"
Browse[2]>
debug at #5: assign(paste("test", instList, sep = "."), function() {
print(instList)
}, envir = .GlobalEnv)
Browse[2]>
debug at #3: instList
Browse[2]> environment(test.CL)
<environment: 0x28e19a8>
Browse[2]> eval(instList, environment(test.CL))
[1] "HO"
循环结束后,assign.instrumentslist()
,<environment: 0x28e19a8>
的评估环境仍然存在,因为它也是三个函数的环境。它们都引用相同的环境,并使用在循环的最后一次迭代期间设置的instList
的值。