问题 在函数内部使用get lapply
这可能看起来像一个过于复杂的问题,但它让我有点疯狂了一段时间。这也是出于好奇,因为我已经有办法做我需要的事情,所以并不重要。
在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)
}
所以当被问到这个时:
> foo(b=0)
$a
[1] 1
$b
[1] 0
$h
[1] "coconut"
这个结果很完美。问题是,当我尝试使用时 lapply
为了达到同样的目标,为了更高效(和优雅),它不能像我想要的那样工作:
foo <- function(a=1, b=5, h='coconut') {
frm <- formals(foo)
parms <- lapply(names(frm), get)
names(parms) <- names(frm)
return(parms)
}
问题显然在于环境 get
计算它的第一个参数(字符串,变量的名称)。我部分地从错误消息中得知:
> foo(b=0)
Error in FUN(c("a", "b", "h")[[1L]], ...) : object 'a' not found
而且,因为在 .GlobalEnv
环境中有正确名称的对象,foo返回其值:
> a <- 100
> b <- -1
> h <- 'wallnut'
> foo(b=0)
$a
[1] 100
$b
[1] -1
$h
[1] "wallnut"
显然,作为 get
默认情况下,计算结果 parent.frame()
,它搜索中的对象 .GlobalEnv
环境,而不是当前功能的环境。这很奇怪,因为函数的第一个版本不会发生这种情况。
我已经尝试了很多选项来实现这个功能 get
在正确的环境中进行评估,但无法正确地进行评估(我已经尝试过了 pos=-2,0,1,2
和 envir=NULL
作为选项)。
如果有人碰巧比我更了解环境,特别是在这个“奇怪”的情况下,我很想知道如何解决这个问题。
谢谢你的时间,
胡安
12694
2017-11-04 22:52
起源
答案:
编辑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')
但是,这没有 sapply()
要么 lapply()
可能是更优雅的解决方案:
foo5 <- function(a=1, b=5, h='coconut') {
modifyList(formals(sys.function()), as.list(match.call())[-1])
}
foo5(b=0, h='mango')
原帖(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"
这里有一些微妙的东西 lapply
scopes /评估它构造的调用。细节隐藏在电话中 .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')
9
2017-11-04 23:41
答案:
编辑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')
但是,这没有 sapply()
要么 lapply()
可能是更优雅的解决方案:
foo5 <- function(a=1, b=5, h='coconut') {
modifyList(formals(sys.function()), as.list(match.call())[-1])
}
foo5(b=0, h='mango')
原帖(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"
这里有一些微妙的东西 lapply
scopes /评估它构造的调用。细节隐藏在电话中 .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')
9
2017-11-04 23:41
只需将当前环境转换为列表:
foo <- function(a=1, b=5, h='coconut') {
as.list(environment())
}
foo(a = 0, h = 'mango')
6
2017-08-07 01:53
这是改编自@Josh O'Brien的上述解决方案 sapply
自动为结果列表分配正确的名称(保存一行代码):
foo <- function(a=1, b=5, h='coconut') {
frm <- formals(foo)
parms <- sapply(names(frm), get, envir=sys.frame(sys.parent(-1)), simplify=FALSE)
return(parms)
}
1
2017-11-04 23:35