在R中使用省略号(“点”)有很多好的(1 2 3)StackOverflow问题。但是,我还没有遇到过一个问题。解决了我的特定用例。我正在努力为函数编写兼容性包装器,该函数将参数名称从原始函数调用更改为基础函数调用。例如,有人可能想要调用newMean(c(1:10,1000,NA),.2,rmNA=TRUE)
而不是mean(c(1:10,1000,NA),.2,na.rm=TRUE)
。我们甚至可能希望以这样的方式编写我们的包装器,即假设所有对newMean的调用都是为mean.default调度的,我们不会杀死S3调用。明显的前进路径就像(伪代码):
newMean <- function(x,...) {
dots <- list(...)
names(dots)[names(dots)=="rmNA"] <- "na.rm"
x.list <- list(x=x)
dots <- c(x.list,dots)
do.call(base::mean,dots)
}
这给我们留下了一个点数值:
dots <- structure(list(x = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1000, NA),
0.2, na.rm = TRUE), .Names = c("x", "", "na.rm"))
到目前为止一切顺利。但事情并不像我原本预期的那样。考虑命令newMean(c(1:10,1000,NA),.2,TRUE)
与base::mean(c(1:10,1000,NA),.2,TRUE)
。当我们调用base::mean
R然后调用mean.default,因为调用中的x的getS3method("base::mean",class(x))
是数字且没有匹配。在调试match.call(mean.default)
时调用的newMean
表明,(未命名的)第二个和第三个参数当然是为了在mean.default中的省略号之前的三个参数分配的。相反,do.call似乎忽略了未命名的参数(可能将它们视为mean.default调用中省略号的一部分?)。
我尝试使用getS3method
识别要使用的S3方法,然后使用formals
挖掘并识别正在调度的特定S3方法的正式参数的数量,但我没有能够生成一种方法来调用mean :: base,它灵活地尊重要调用的方法中存在的形式的数量并适当地匹配它们。
如果不解除从newMean到base的匹配调用:mean(例如deparse(match.call(base::mean))
)并手动修改参数名称,是否有办法修复newMean的行为以使trim和na.rm适当匹配?我不希望字符串操作参数名称的替换的原因是我可以想象的情况(在这个玩具示例之外),其中调用中的值可能与参数名称部分匹配。
答案 0 :(得分:2)
一种方法是修改对newMean()
的调用,并将其更改为对base::mean()
的调用:
newMean <- function(...) {
call <- match.call()
call[[1]] <- quote(base::mean)
rmNA <- names(call) == "rmNA"
names(call)[rmNA] <- "na.rm"
eval(call, parent.frame())
}
newMean(c(1:10, NA), rmNA = T)
但这比简单的更糟糕了:
newMean <- function(x, trim = 0, rmNA = FALSE, ...) {
mean(x, trim = trim, na.rm = rmNA, ...)
}
答案 1 :(得分:0)
正如我所指出的那样,我并不完全确定你的目标是什么,但如果您想要的只是将未命名的参数列表转换为可以传递给mean.default
的参数列表,那么它就会如此简单为:
newMean <- function(x,...) {
dots <- list(...)
mean(x, trim = dots[[1]], na.rm = dots[[2]] )
}
这种简单易行性使我认为我不理解您遇到的问题或错误,但这证明了名称在存在时的匹配:
newMean.partial <- function(x,...) {
dots <- list(...)
names(dots)[names(dots)=="rmNA"] <- "na.rm"
x.list <- list(x=x)
dots <- c(x.list,dots)
print(dput(dots))
}
newMean.partial(c(1:10,1000,NA),.2,rmNA=TRUE)
# structure(list(x = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1000, NA),
# 0.2, na.rm = TRUE), .Names = c("x", "", "na.rm"))