使用以下函数foo()
作为一个简单示例,如果可能的话,我想分发...
两个不同函数中给出的值。
foo <- function(x, y, ...) {
list(sum = sum(x, ...), grep = grep("abc", y, ...))
}
在以下示例中,我希望将na.rm
传递给sum()
,并将value
传递给grep()
。但是我在grep()
中找到了一个未使用的参数的错误。
X <- c(1:5, NA, 6:10)
Y <- "xyzabcxyz"
foo(X, Y, na.rm = TRUE, value = TRUE)
# Error in grep("abc", y, ...) : unused argument (na.rm = TRUE)
似乎首先将参数发送给grep()
。那是对的吗?我认为R会首先看到并评估sum()
,并为该情况返回错误。
此外,当试图在...
中分割论据时,我遇到了麻烦。 sum()
的正式论据是NULL
,因为它是.Primitive
,因此我无法使用
names(formals(sum)) %in% names(list(...))
我也不想假设来自
的剩余参数names(formals(grep)) %in% names(list(...))
会自动传递给sum()
。
如何安全有效地将...
参数分发给多个函数,以便不进行不必要的评估?
从长远来看,我希望能够将此应用于包含...
个参数列表的函数,类似于download.file()
和scan()
的参数。< / p>
答案 0 :(得分:25)
单独列表如果您真的想将不同的参数集传递给不同的函数,那么指定单独的列表可能更简洁:
foo <- function(x, y, sum = list(), grep = list()) {
list(sum = do.call("sum", c(x, sum)), grep = do.call("grep", c("abc", y, grep)))
}
# test
X <- c(1:5, NA, 6:10)
Y <- "xyzabcxyz"
foo(X, Y, sum = list(na.rm = TRUE), grep = list(value = TRUE))
## $sum
## [1] 55
##
## $grep
## [1] "xyzabcxyz"
混合列表/ ... 另一种选择是我们可以使用...作为其中之一,然后将另一个指定为列表,特别是在经常使用其中一个的情况下而另一种则很少使用。经常使用的一个将通过...传递,并且通过列表不经常使用。 e.g。
foo <- function(x, y, sum = list(), ...) {
list(sum = do.call("sum", c(x, sum)), grep = grep("abc", y, ...))
}
foo(X, Y, sum = list(na.rm = TRUE), value = TRUE)
以下是R本身的混合方法的几个例子:
i)mapply
函数使用...
和MoreArgs
列表采用该方法:
> args(mapply)
function (FUN, ..., MoreArgs = NULL, SIMPLIFY = TRUE, USE.NAMES = TRUE)
NULL
ii)nls
也使用...
和control
列表采用此方法:
> args(nls)
function (formula, data = parent.frame(), start, control = nls.control(),
algorithm = c("default", "plinear", "port"), trace = FALSE,
subset, weights, na.action, model = FALSE, lower = -Inf,
upper = Inf, ...)
NULL
答案 1 :(得分:13)
为什么grep
之前sum
错误?
看到sum
更适合其论点:
X <- c(1:5, NA, 6:10)
sum(X, na.rm = TRUE, value = TRUE)
## [1] 56
它没有失败,因为它并不关心其他命名参数,因此value = TRUE
简化为TRUE
,总和为1.顺便提一下:
sum(X, na.rm = TRUE)
## [1] 55
如何将...
拆分为不同的功能?
一种方法(非常容易出错)是查找目标函数的args。例如:
foo <- function(x, y, ...){
argnames <- names(list(...))
sumargs <- intersect(argnames, names(as.list(args(sum))))
grepargs <- intersect(argnames, names(as.list(args(grep))))
list(sum = do.call(sum, c(list(x), list(...)[sumargs])),
grep = do.call(grep, c(list("abc", y), list(...)[grepargs])))
}
如果args
未正确报告函数使用的参数(例如S3对象),则很容易出错。举个例子:
names(as.list(args(plot)))
## [1] "x" "y" "..." ""
names(as.list(args(plot.default)))
## [1] "x" "y" "type" "xlim" "ylim"
## [6] "log" "main" "sub" "xlab" "ylab"
## [11] "ann" "axes" "frame.plot" "panel.first" "panel.last"
## [16] "asp" "..." ""
在这种情况下,您可以替换相应的S3功能。因此,我没有这方面的通用解决方案(虽然我不知道它确实存在或不存在)。
答案 2 :(得分:0)
如果其他函数包含您传递给...
的所有命名参数,或者它本身有...
参数,则只能将...
参数传递给另一个函数。因此对于sum
,这没有问题(args(sum)
返回function (..., na.rm = FALSE)
)。另一方面,grep
既没有na.rm
也没有...
作为参数。
args(grep)
# function (pattern, x, ignore.case = FALSE, perl = FALSE, value = FALSE,
# fixed = FALSE, useBytes = FALSE, invert = FALSE)
这不包括...
,也不包括命名参数na.rm
。一个简单的解决方案是定义您自己的函数mygrep
,如下所示:
mygrep <- function (pattern, x, ignore.case = FALSE, perl = FALSE, value = FALSE,
fixed = FALSE, useBytes = FALSE, invert = FALSE, ...)
grep(pattern, x, ignore.case, perl, value, fixed, useBytes, invert)
然后似乎有效:
foo <- function(x, y, ...){
list(sum = sum(x, ...), grep = mygrep("abc", y, ...))
}
X <- c(1:5, NA, 6:10)
Y <- "xyzabcxyz"
foo(X, Y, na.rm = TRUE, value = TRUE)
# $sum
# [1] 56
#
# $grep
# [1] "xyzabcxyz"