[英]Error in using match.arg for multiple arguments
我不熟悉在 R 函数中使用match.arg
作为默认值规范。 我对以下行为有疑问。
trial_func <- function(a=c("1","9","20"),b=c("12","3"),d=c("55","01")){
a <- match.arg(a)
b <- match.arg(b)
d <- match.arg(d)
list(a,b,d)
}
trial_func()
# [[1]]
# [1] "1"
#
# [[2]]
# [1] "12"
#
# [[3]]
# [1] "55"
当我尝试对每个单独的参数使用match.arg
时,它按预期工作。 但是当我尝试使用 lapply 来减少编写的代码时,会导致以下问题。
trial_func_apply <- function(a=c("1","9","20"),b=c("12","3"),d=c("55","01")){
lapply(list(a,b,d), match.arg)
}
trial_func_apply()
FUN(X[[i]], ...) 中的错误:“arg”的长度必须为 1
我在这里错过了什么吗?
经过一番调查之后,您需要传递一个论点,即您的字符向量为NULL,即
trial_func_apply <- function(a=c("1","9","20"),b=c("12","3"),d=c("55","01")){
lapply(list(a,b,d), function(i)match.arg(NULL, i))
}
trial_func_apply()
#[[1]]
#[1] "1"
#[[2]]
#[1] "12"
#[[3]]
#[1] "55"
这是一个老问题,但我觉得这是一个很好的问题,所以我将尝试通过解释以下内容来提供广泛的解释:
?match.arg
的相关文档match.arg
无法猜测选择match.arg
在下面使用的 R 语言的三个功能。match.arg
实现lapply
示例有效match.arg
文档用法告诉您match.arg
需要您要匹配的选定选项 ( arg
) 和所有可能的choices
:
match.arg(arg, choices, several.ok = FALSE)
如果我们阅读choices
,我们会发现它经常会丢失,我们应该阅读更多细节...... match.arg
如何在没有可能的选择的情况下工作,我们想知道?
选择:候选值的特征向量,通常缺失,请参阅“详细信息”。
也许细节部分给出了一些提示(粗体是我的):
细节:
在单参数形式“match.arg(arg)”中,选择是从调用“match.arg”的 function 的正式参数“arg”的默认设置中获得的。 (由于默认参数匹配会将 'arg' 设置为 'choices',这被允许作为 'length one unless 'several.ok' is 'TRUE'' 规则的例外,并返回第一个元素。)
因此,如果您不指定choices
参数,R 将付出一些努力自动猜对它。 要使 R 魔法起作用,必须满足几个条件:
match.arg
functionmatch.arg()
可以被欺骗: 让match.arg()
无法猜测选择:
dummy_fun1 <- function(x = c("a", "b"), y = "c") {
# If you name your argument like another argument
y <- x
# The guessed choices will correspond to y (how could it know they were x?)
wrong_choices <- match.arg(y)
}
dummy_fun1(x = "a")
# Error in match.arg(y) : 'arg' should be “c”
dummy_fun2 <- function(x = c("a", "b"), y = "c") {
# If you name your argument differently
z <- x
# You don't get any guess:
wrong_choices <- match.arg(z)
}
dummy_fun2(x="a")
#Error in match.arg(z) : 'arg' should be one of
(1) 它使用非标准评估来获取变量的名称:
whats_the_var_name_called <- function(arg) {
as.character(substitute(arg))
}
x <- 3
whats_the_var_name_called(x)
# "x"
y <- x
whats_the_var_name_called(y)
# "y"
(2) 它使用sys.function()
获取调用者 function:
this_function_returns_its_caller <- function() {
sys.function(1)
}
this_function_returns_itself <- function() {
me <- this_function_returns_its_caller()
message("This is the body of this_function_returns_itself")
me
}
> this_function_returns_itself()
This is the body of this_function_returns_itself
function() {
me <- this_function_returns_its_caller()
message("This is the body of this_function_returns_itself")
me
}
(3) 它使用formals()
来获取可能的值:
a_function_with_default_values <- function(x=c("a", "b"), y = 3) {
}
formals(a_function_with_default_values)[["x"]]
#c("a", "b")
match.arg
是如何工作的? 结合这些东西, match.arg
使用substitute()
来获取 args 变量的名称,它使用sys.function()
来获取调用者 function,并在调用者 function 上使用带有参数名称的formals()
来获取function 的默认值(选项):
get_choices <- function(arg, choices) {
if (missing(choices)) {
arg_name <- as.character(substitute(arg))
caller_fun <- sys.function(1)
choices_as_call <- formals(caller_fun)[[arg_name]]
choices <- eval(choices_as_call)
}
choices
}
dummy_fun3 <- function(x = c("a", "b"), y = "c") {
get_choices(x)
}
dummy_fun3()
#[1] "a" "b"
由于我们现在知道用于获得选择的魔法,所以我们可以创建我们的match.arg
实现:
my_match_arg <- function(arg, choices) {
if (missing(choices)) {
arg_name <- as.character(substitute(arg))
caller_fun <- sys.function(1)
choices_as_call <- formals(caller_fun)[[arg_name]]
choices <- eval(choices_as_call)
}
# Really simple and cutting corners... but you get the idea:
arg <- arg[1]
if (! arg %in% choices) {
stop("Wrong choice")
}
arg
}
dummy_fun4 <- function(x = c("a", "b"), y = "c") {
my_match_arg(x)
}
dummy_fun4(x="d")
# Error in my_match_arg(x) : Wrong choice
dummy_fun4(x="a")
# [1] "a"
这就是match.arg
的工作原理。
lapply
下不起作用? 如何解决? 为了猜测choices
参数,我们查看调用者参数。 当我们在 lapply 调用中使用match.arg()
时,调用者不是我们的 function,因此match.arg
无法猜测choices
。 我们可以手动获取选项并手动提供选项:
trial_func_apply <- function(a=c("1","9","20"),b=c("12","3"),d=c("55","01")){
this_func <- sys.function()
the_args <- formals(this_func)
default_choices <- list(
eval(the_args[["a"]]),
eval(the_args[["b"]]),
eval(the_args[["d"]])
)
# mapply instead of lapply because we have two lists we
# want to apply match.arg to
mapply(match.arg, list(a,b,d), default_choices)
}
trial_func_apply()
# [1] "1" "12" "55"
请注意,我通过不定义所有评估应该发生的环境来偷工减料,因为在上面的示例中它们按原样工作。 可能有一些极端情况会使这个示例失败,所以不要在生产中使用它们。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.