在R中有以下代码:
named_list = list()
for (i in 1:5){
named_list[[i]] = function(one,two){c(one,two, i)}
}
但是,当我调用该函数时:
> named_list[[1]]("first", "second")
[1] "first" "second" "5"
有没有一种方法可以让它正常工作(返回“first”,“second”,“1”)而不使用apply函数?我已经尝试使用力功能的建议,在另一个线程,但我不能让它工作。
谢谢
编辑:为了澄清一些问题,我希望制作一个函数列表,每个函数都包含该函数在该列表中的位置的索引。特别是,请注意
> named_list[[1]]("first", "second")
[1] "first" "second" "5"
> named_list[[2]]("first", "second")
[1] "first" "second" "5"
> named_list[[3]]("first", "second")
[1] "first" "second" "5"
> named_list[[4]]("first", "second")
[1] "first" "second" "5"
> named_list[[5]]("first", "second")
[1] "first" "second" "5"
这显然不是期望的行为。问题是,通过1到5循环i,R看到第一个'i'索引named_list,但看不到第二个'i',它在我试图定义的函数中。
我知道以下是一个可能的解决方案(尽管我不知道 * 为什么 * 它有效):
named_list = lapply(1:5, function(i) function(one,two)(c(one,two,i)))
但我想知道是否有使用for循环的替代解决方案。
2条答案
按热度按时间gzszwxb41#
我认为您的问题与 scope 或 namespace 有关。也就是说,当在一个函数中引用了一个没有在该函数中本地定义的变量时,R开始在父“框架”(定义其变量的环境)中搜索;如果不存在,则它转到父的父帧(祖-父帧?);等等。(一个很好的阅读是Advanced R: Environments;额外的阅读可能是同一本书关于Memory的章节。
查看在任何给定时间正在使用/搜索的
environment
是很有帮助的。我将重点介绍当前环境、父环境以及函数内部的“祖父”环境;但是,我意识到,深度嵌套的函数可能有更多的变量(这表明当依赖R来查找并找到不在本地环境中的变量的特定示例时,您需要非常小心!).注意:你很可能不会得到相同的
<environment: 0x000...>
指针。这些引用是完全不可复制的,并且在每次运行此代码时都会更改。让我们从
lapply
设置 * 开始:首先要注意,
lapply
中的每次迭代都有一个新的环境,从9128fe0
开始,其父环境是全局env。在lapply
的第二次迭代中,我们在90bb578
中,在该环境中,我们定义了function(one,two)
,其本地环境是8f811b8
(我们在下一个代码块中看到)。请注意,此时R尚未尝试解析
i
。让我们运行一个函数:因此,当我们引用
i
时,R按顺序搜索以下内容以找到它:8f811b8
:在function(one,two)...
内部,未找到90bb578
:直接父环境,在function(i) ...
内部;找到R_GlobalEnv
(未搜索,因为之前已找到)好的,让我们试试
for
循环:首先要注意的是,在
for
循环的每次迭代中,本地环境是R_GlobalEnv
,这应该是有意义的。(您可以安全地忽略对父环境tcltk
的引用。)好了,现在当我们到达
nl2[[1]]
调用时,请注意父环境是R_GlobalEnv
环境(现在可能是这样,这并不奇怪):这是R第一次需要 find
i
,所以它首先在1b1a6720
中搜索(在function(one,two)
中,没有找到它),然后在R_GlobalEnv
中搜索。为什么返回“2”?
因为在我们调用
nl2[[2]]
时,R_GlobalEnv
中i
的值是for
循环中i
的最后一个值。看这个:更重要的是,如果我们现在尝试调用函数:
因此,该函数中
i
的计算是惰性的,因为它会在您调用该函数时进行搜索。在您的环境中(在更改任何代码之前),如果键入
i <- 100
,您将看到类似的行为。如果您绝对反对使用
lapply
(这是我在这里的首选方法,即使我不理解您在这里的底层需求),请尝试显式地定义函数周围的环境。一种方法是使用local
,它将保留在现有父环境中的搜索,同时允许我们“强制”使用我们想要使用的i
。(还有其他选择,我邀请其他人发表评论,并让您更多地探索环境。(You可能会注意到,每次调用该函数时,本地环境都会发生变化,而父函数则不会。这是因为当你调用一个函数时,它会在函数调用的开始处开始一个新的环境。你“知道”并依赖于这一点,因为你假设在你的函数开始时,没有定义任何变量。这是正常的)。
db2dz4w82#
每当我遇到这种情况时,我决定将其作为文本写出来,并将其 Package 在eval语句中。像这样
现在我得到了
如你所愿。
所以我所做的就是让我知道我想要的字符串在文本中,并让它以这种方式计算它。
可能有更好的解决方案,但这将为您做的工作。