在R 3.0.2中,missing()函数可以告诉我们是否缺少形式参数。
如何避免硬编码传递给丢失的变量名?例如在
demoargs <- function(a=3, b=2, d) {
f <- formals(demoargs) # Capture formal arguments
formalNames <- names(f) # get variable names: a, b, d
...
}
我希望能够以硬编码的方式检查缺少的形式,例如:
missing(formalNames[1]) # returns invalid use of missing!
与缺少(d)相反,目的是迭代以有限数量的方式处理的大量可选参数。我曾希望得到或as.name我把我放在正确的轨道上,但似乎并非如此。
或者,我怀疑我可以使用vararg参数(...)执行此操作,但调用者能够通过检查函数声明来检查可接受的可选参数会很好。
谢谢, 玛丽
答案 0 :(得分:6)
您可能首先尝试了类似missing(as.name(formalNames[1]))
或missing(formalNames[1])
的内容,但发现它们无效。
他们没有理由missing()
是其中一个奇怪的功能 - library()
和debug()
是其他几个 - 这将作为一个论点接受名称的名称或字符表示。那很不错&#39;在某种意义上,missing(a)
和missing("a")
都将检查函数调用是否包含提供的参数a
;当你执行missing(formalNames[1])
并且找到一个名为formalNames[1]
的不存在的参数时,它就不那么好了。
解决方案是使用do.call()
,它会在将第二个参数传递给第一个参数中给出的函数之前计算其第二个参数的元素。以下是您可能会做的事情:
demoargs <- function(a=3, b=2, d) {
formalNames <- names(formals()) # get variable names: a, b, d
do.call(missing, list(formalNames[1]))
}
## Try it out
demoargs(a=42)
# [1] FALSE
demoargs()
# [1] TRUE
答案 1 :(得分:0)
我们可以构建调用missing("a")
,然后对其进行评估,可以通过不同的方式进行:
demoargs1 <- function(a=3, b=2, d) {
formalNames <- names(formals())
eval(bquote(missing(.(formalNames[1]))))
}
demoargs1(3)
#> [1] FALSE
demoargs1()
#> [1] TRUE
demoargs2 <- function(a=3, b=2, d) {
formalNames <- names(formals())
eval(substitute(missing(X), list(X = formalNames[1])))
}
demoargs2(3)
#> [1] FALSE
demoargs2()
#> [1] TRUE
demoargs3 <- function(a=3, b=2, d) {
formalNames <- names(formals())
eval(call("missing", formalNames[1]))
}
demoargs3(3)
#> [1] FALSE
demoargs3()
#> [1] TRUE
demoargs4 <- function(a=3, b=2, d) {
formalNames <- names(formals())
eval(as.call(c(quote(missing), formalNames[1])))
}
demoargs4(3)
#> [1] FALSE
demoargs4()
#> [1] TRUE
另一种方法是检查参数是否在调用中:
demoargs5 <- function(a=3, b=2, d) {
formalNames <- names(formals())
formalNames[1] %in% names(match.call()[-1])
}
demoargs5(3)
#> [1] TRUE
demoargs5()
#> [1] FALSE
让我们将Josh的建议添加到批处理中并对它们进行基准测试:
demoargs_josh <- function(a=3, b=2, d) {
formalNames <- names(formals())
do.call(missing, list(formalNames[1]))
}
microbenchmark::microbenchmark(
demoargs_josh(),
demoargs1(),
demoargs2(),
demoargs3(),
demoargs4(),
demoargs5(),times = 100000)
#> Unit: microseconds
#> expr min lq mean median uq max neval cld
#> demoargs_josh() 2.5 3.1 5.237294 3.5 4.4 7389.8 1e+05 a
#> demoargs1() 11.7 13.4 21.198503 14.0 19.0 5708.1 1e+05 e
#> demoargs2() 3.1 3.7 6.158610 4.0 5.1 6628.5 1e+05 c
#> demoargs3() 2.8 3.3 5.465650 3.7 4.6 2936.4 1e+05 ab
#> demoargs4() 2.9 3.5 5.712464 3.8 4.9 2104.8 1e+05 b
#> demoargs5() 5.1 6.2 10.056112 6.7 8.7 6204.4 1e+05 d
由reprex package(v0.3.0)于2019-10-24创建
使用do.call()
的速度似乎稍快,但是使用call()
或as.call()
则显示出非常相似的性能。