因此,请考虑以下大部分代码,这些代码无法像大多数人所希望的那样工作
#cartoon example
a <- c(3,7,11)
f <- list()
#manual initialization
f[[1]]<-function(x) a[1]+x
f[[2]]<-function(x) a[2]+x
f[[3]]<-function(x) a[3]+x
#desired result for the rest of the examples
f[[1]](1)
# [1] 4
f[[3]](1)
# [1] 12
#attempted automation
for(i in 1:3) {
f[[i]] <- function(x) a[i]+x
}
f[[1]](1)
# [1] 12
f[[3]](1)
# [1] 12
请注意,在我们尝试&#34;自动化&#34;后,我们都会得到12次。当然,问题是i
并未包含在函数的私有环境中。所有函数在全局环境中引用相同的i
(它只能有一个值),因为for循环似乎不会为每次迭代创建不同的环境。
sapply(f, environment)
# [[1]]
# <environment: R_GlobalEnv>
# [[2]]
# <environment: R_GlobalEnv>
# [[3]]
# <environment: R_GlobalEnv>
所以我虽然可以使用local()
和force()
来捕捉i
值
for(i in 1:3) {
f[[i]] <- local({force(i); function(x) a[i]+x})
}
f[[1]](1)
# [1] 12
f[[3]](1)
# [1] 12
但这仍然无法奏效。我可以看到它们都有不同的环境(通过sapply(f, environment)
),但它们似乎是空的(ls.str(envir=environment(f[[1]]))
)。将此与
for(i in 1:3) {
f[[i]] <- local({ai<-i; function(x) a[ai]+x})
}
f[[1]](1)
# [1] 4
f[[3]](1)
# [1] 12
ls.str(envir=environment(f[[1]]))
# ai : int 1
ls.str(envir=environment(f[[3]]))
# ai : int 3
很明显force()
并没有像我期待的那样工作。我假设它会将i
的当前值捕获到当前环境中。它在像
#bad
f <- lapply(1:3, function(i) function(x) a[i]+x)
#good
f <- lapply(1:3, function(i) {force(i); function(x) a[i]+x})
其中i
作为参数/承诺传递,但这绝不是for-loop中发生的事情。
所以我的问题是:是否可以在没有local()
和变量重命名的情况下创建这个函数列表?是否有比force()
更合适的函数,它将从父框架中捕获变量的值到本地/当前环境中?
答案 0 :(得分:4)
这不是一个完整的答案,部分是因为我不确定究竟是什么问题(即使我发现它很有趣!)。
相反,我只提出两个可行的for
- 循环。他们帮助澄清了我脑海中的问题(尤其是帮助我第一次理解force()
在调用lapply()
时做了什么。我希望他们也会帮助你。
首先,这是一个与正确的函数lapply()
调用更接近的函数,它的作用与它的作用相同:
a <- c(3,7,11)
f <- list()
## `for` loop equivalent of:
## f <- lapply(1:3, function(i) {force(i); function(x) a[i]+x})
for(i in 1:3) {
f[[i]] <- {X <- function(i) {force(i); function(x) a[i]+x}; X(i)}
}
f[[1]](1)
# [1] 4
其次,这是一个使用local()
但没有(严格地或字面地说)重命名i
的人。但它确实通过将其副本添加到本地环境来“重新屏蔽”它。从某种意义上说,它与你的功能for
循环只是微不足道,但是通过关注i
的范围,而不是它的名称,我认为它有助于揭示你的潜在问题。问题
a <- c(3,7,11)
f <- list()
for(i in 1:3) {
f[[i]] <- local({i<-i; function(x) a[i]+x})
}
f[[1]](1)
# [1] 4
答案 1 :(得分:1)
这种方法对你有用吗?
ff<-list()
for(i in 1:3) {
fillit <- parse(text=paste0('a[',i,']+x' ))
ff[[i]] <- function(x) ''
body(ff[[i]])[1]<-fillit
}
它是一种构建函数的低级方法,但它确实可以“按照你的意愿”工作。
答案 2 :(得分:0)
可以在for循环本地环境中使用的force()
的替代方法是
capture <- function(...) {
vars<-sapply(substitute(...()), deparse);
pf <- parent.frame();
Map(assign, vars, mget(vars, envir=pf, inherits = TRUE), MoreArgs=list(envir=pf))
}
然后可以像
一样使用for(i in 1:3) {
f[[i]] <- local({capture(i); function(x) a[i]+x})
}
(取自Josh上面回答的评论)