这看起来似乎是一个过于复杂的问题,但它让我有点疯狂了一段时间.这也是为了好奇,因为我已经有办法做我需要的事情,所以并不重要.
在R中,我需要一个函数来返回一个带有所有参数和用户输入的值的命名列表对象.为此,我制作了这个代码(玩具示例):
foo <- function(a=1, b=5, h='coconut') {
frm <- formals(foo)
parms <- frm
for (i in 1:length(frm))
parms[[i]] <- get(names(frm)[i])
return(parms)
}
Run Code Online (Sandbox Code Playgroud)
所以当被问到这个时:
> foo(b=0)
$a
[1] 1
$b
[1] 0
$h
[1] "coconut"
Run Code Online (Sandbox Code Playgroud)
这个结果很完美.问题是,当我尝试使用lapply相同的目标时,为了更高效(和优雅),它不能像我想要的那样工作:
foo <- function(a=1, b=5, h='coconut') {
frm <- formals(foo)
parms <- lapply(names(frm), get)
names(parms) <- names(frm)
return(parms)
}
Run Code Online (Sandbox Code Playgroud)
问题显然在于get评估它的第一个参数的环境(字符串,变量的名称).我部分地从错误消息中得知:
> foo(b=0)
Error in FUN(c("a", "b", "h")[[1L]], ...) : object 'a' not found
Run Code Online (Sandbox Code Playgroud)
而且,因为在.GlobalEnv环境中有正确名称的对象,foo会返回它们的值:
> a <- 100
> b <- -1
> h <- 'wallnut'
> foo(b=0)
$a
[1] 100
$b
[1] -1
$h
[1] "wallnut"
Run Code Online (Sandbox Code Playgroud)
显然,正如get默认情况下在其中进行求值一样parent.frame(),它会搜索.GlobalEnv环境中的对象,而不是当前函数的对象.这很奇怪,因为函数的第一个版本不会发生这种情况.
我已经尝试了很多选项来使函数get在正确的环境中进行评估,但是无法正确执行(我已经尝试过pos=-2,0,1,2并envir=NULL作为选项).
如果有人碰巧比我更了解环境,特别是在这个"奇怪"的情况下,我很想知道如何解决这个问题.
谢谢你的时间,
胡安
Jos*_*ien 11
编辑2013-08-05
使用sapply()而不是lapply()简化:
foo4 <- function(a=1, b=5, h='coconut') {
frm <- formals(sys.function())
sapply(names(frm), get, envir=sys.frame(sys.parent(0)), simplify=FALSE)
}
foo4(b=0, h='mango')
Run Code Online (Sandbox Code Playgroud)
但是,没有sapply() 或 lapply()可能是更优雅的解决方案:
foo5 <- function(a=1, b=5, h='coconut') {
modifyList(formals(sys.function()), as.list(match.call())[-1])
}
foo5(b=0, h='mango')
Run Code Online (Sandbox Code Playgroud)
原帖(2011-11-04)
在铸造了一下之后,这看起来是最好的解决方案.
foo <- function(a=1, b=5, h='coconut') {
frm <- formals(foo)
parms <- lapply(names(frm), get, envir=sys.frame(sys.parent(0)))
names(parms) <- names(frm)
return(parms)
}
foo(b=0, h='mango')
# $a
# [1] 1
# $b
# [1] 0
# $h
# [1] "mango"
Run Code Online (Sandbox Code Playgroud)
这里有一些微妙的东西,其lapply范围/评估它构造的调用.细节隐藏在一个电话中.Internal(lapply(X, FUN)),但为了品味,请比较这两个电话:
# With function matched by match.fun, search in sys.parent(0)
foo2 <- function(a=1, h='coconut') {
lapply(names(formals()),
get, envir = sys.parent(0))
}
# With anonymous function, search in sys.parent(2)
foo3 <- function(a=1, h='coconut') {
lapply(names(formals()),
FUN = function(X) get(X, envir = sys.parent(2)))
}
foo4(a=0, h='mango')
foo5(a=0, h='mango')
Run Code Online (Sandbox Code Playgroud)
只需将当前环境转换为列表:
foo <- function(a=1, b=5, h='coconut') {
as.list(environment())
}
foo(a = 0, h = 'mango')
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3532 次 |
| 最近记录: |