如何在没有deparse的情况下将省略号转换为列表并返回到R中的原始调用

时间:2013-11-27 07:41:18

标签: r class ellipsis

在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适当匹配?我不希望字符串操作参数名称的替换的原因是我可以想象的情况(在这个玩具示例之外),其中调用中的值可能与参数名称部分匹配。

2 个答案:

答案 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"))