这个问题与我原来的不一样;它更多地依赖于 minimal 可重现的示例,并包含be_green的建议,以防止在函数的上下文中静默加载整个库。
外部函数首先定义多个案例,默认值和任何案例例外列表。除非定义了异常,否则内部函数通过使用计算中的默认值来组装每种情况。最后,外部函数将这些情况组合成一个数据框。
这是功能:
outerfun <- function(cases, var_default, exceptions=list()){
# Inner Function to create a case
innerfun <- function(var=var_default) { # Case
result = var
return(result)
}
# Combine Cases
datlist <- list()
for(case in 1:cases){
datlist[[paste0("X",case)]] <- do.call(innerfun, as.list(exceptions[[paste0("X",case)]]))
}
casedata <- do.call(dplyr::data_frame, datlist)
return(casedata)
}
当我将内部函数的值定义为例外时,此函数正常工作:
data <- outerfun(cases = 3, var_default = 10, exceptions = list("X2" = c(var = 14)))
但是当我把两者混合时不是这样的:
data <- outerfun(cases = 3, var_default = 10, exceptions =
list("X2" = c(var = var_default + 4)))
能够将两者混合是很重要的,因为它使功能更直观,更容易为各种情况编程。
我认为问题可能来自使用do.call并且已经看到其他线程详细说明了这个问题(与环境和框架有关),但我还没有能够为我找到最佳解决方案。我喜欢do.call,因为我可以将一个参数列表传递给一个函数。我可以将内部函数转换为一个列表(想想:function(...){})但是我必须定义每个变量而不是依赖于默认值。
您可能获得的任何帮助或建议都会很棒。
答案 0 :(得分:1)
问题是lvl_default
未在函数的上下文之外定义,但您将其称为参数的输入。因为在全局环境中没有名为lvl_default
的变量,所以当函数尝试计算参数exceptions = list(X3 - c(lvl = lvl_default + 10)
时,它无法找到要评估的变量。您无法通过将参数设置为等于其他未评估参数的名称来指定参数。
相反,我建议做的是在与您希望传递给lvl_default
的值相关联的函数之外设置一个变量,然后将其传递给函数,如下所示:
level <- 1000
data <- genCaseData(n_signals = 3, datestart = "2017-07-01T15:00:00",
n_cycles = 4, period_default = 10, phase_default = 0, ampl_default = 15,
lvl_default = level, exceptions = list(X1= c(lvl=980),
X3 = c(lvl = level + 10)))
正如我在评论中指出的那样,我建议不要在函数的上下文中静默加载整个库。你可以最终掩盖你不想要的东西,并遇到奇怪的错误,因为如果库不可用,require调用实际上不会抛出一个。相反,我会通过pkgname::fncname
引用这些功能。
答案 1 :(得分:0)
be_green 首先解决了这个问题,但我想跟进我实际为项目做的事情。
正如 be_green 指出的那样,我无法在例外列表中调用var_default
,因为它尚未定义。我一开始并不理解这一点,因为你可以实际定义函数本身定义的变量的参数的默认值:
addfun <- function(x, y = z + x + 2) {
z = 20
c(x, y)
}
addfun(x = 20)
[1] 20 42
这是因为R lazily evaluated中的函数参数。我认为这给了我一个传递来调用这个函数:
addfun(x = 10, y = x + z)
addfun中的错误(x = 10,y = x + z):object&#39; x&#39;找不到
如果您移除x
,则会调用z
的错误。因此,即使y
的默认值取决于x
和z
,您也无法使用x
或z
来调用该函数。
be_green 建议我在字符串中传递参数,然后在函数中解析它。但我担心我的团队中的其他人会发现结果语法令人困惑。
相反,我使用了省略号(...
)并评估了函数中的省略号参数。我使用这行代码完成了这个:
list2env(eval(substitute(alist(...))), envir = as.environment(-1))
此处eval(substitute(alist(...)))
模式很常见,但会生成一个命名的参数列表。由于某些其他功能,将参数作为函数内的对象进行评估变得更加方便。 list2env(x, envir = as.environment(-1))
通过额外的步骤完成此任务。调用参数后,您需要显式评估调用。因此,如果我想更改上面的addfun()
:
addfun <- function(x, ...) {
z = 20
list2env(eval(substitute(alist(...))),
envir = as.environment(-1))
c(x, eval(y))
}
addfun(x = 10, y = x + z)
这是一个陈腐的例子:我现在需要定义y
,即使它不是函数中的参数。但现在我甚至可以在函数调用中重新定义z
:
addfun(x = 10, y = z + 2, z = 10)
由于non-standard evaluation,这一切都是可能的。可以进行权衡,但在我的非标准评估应用中,我能够提高功能的可用性和灵活性,同时使其更直观易用。
最终代码:
outerfun <- function(caseIDs, var_default, ...){
list2env(eval(substitute(alist(...))), envir = as.environment(-1))
# Inner Function to create a case
innerfun <- function(var=var_default) { # Case
result = var
return(result)
}
# Combine Cases
datlist <- lapply(caseIDs, function(case) {
do.call(innerfun, eval(get0(case, ifnotfound = list())))
})
names(datlist) <- caseIDs
casedata <- do.call(dplyr::data_frame, datlist)
return(casedata)
}
现在这两个示例都具有完整功能:
data <- outerfun(caseIDs = c("X1","X2","X3"), var_default = 10,
X2 = list(var = 14))
data <- outerfun(caseIDs = c("X1","X2","X3"), var_default = 10,
X2 = list(var = var_default + 4))
我希望这有助于其他人!享受!