[英]Using get inside lapply, inside a function
這看起來似乎是一個過於復雜的問題,但它讓我有點瘋狂了一段時間。 這也是為了好奇,因為我已經有辦法做我需要的事情,所以並不重要。
在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
和pos=-2,0,1,2
envir=NULL
作為選項)。
如果有人碰巧比我更了解環境,特別是在這個“奇怪”的情況下,我很想知道如何解決這個問題。
謝謝你的時間,
胡安
編輯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
范圍/評估它構造的調用的方式。 細節隱藏在對.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')
只需將當前環境轉換為列表:
foo <- function(a=1, b=5, h='coconut') {
as.list(environment())
}
foo(a = 0, h = 'mango')
這是從@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)
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.