拆分`...`参数并分配给多个函数

Ric*_*ven 28 r

使用以下函数foo()作为一个简单的例子...,如果可能的话,我想分发两个不同函数给出的值.

foo <- function(x, y, ...) {
    list(sum = sum(x, ...), grep = grep("abc", y, ...))
}
Run Code Online (Sandbox Code Playgroud)

在下面的例子中,我希望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)
Run Code Online (Sandbox Code Playgroud)

看起来这些论点grep()首先被发送出去了.那是对的吗?我认为R会sum()首先看到并评估,并为该情况返回错误.

此外,当试图分裂论点时...,我遇到了麻烦. sum()正式的论据是NULL因为它是一个.Primitive,因此我无法使用

names(formals(sum)) %in% names(list(...))
Run Code Online (Sandbox Code Playgroud)

我也不想假设剩下的论据来自

names(formals(grep)) %in% names(list(...))
Run Code Online (Sandbox Code Playgroud)

是自动传递给sum().

如何安全有效地将...参数分配给多个函数,以便不进行不必要的评估?

从长远来看,我希望能够将这个应用于具有长...参数列表的函数,类似于download.file()scan().

G. *_*eck 28

单独的列表如果您确实希望将不同的参数集传递给不同的函数,那么指定单独的列表可能更简洁:

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"
Run Code Online (Sandbox Code Playgroud)

混合列表/ ...另一种选择是我们可以使用...作为其中之一,然后将另一个指定为列表,特别是在经常使用其中一个而另一个不经常使用的情况下.经常使用的一个将通过...传递,并且通过列表不经常使用.例如

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)
Run Code Online (Sandbox Code Playgroud)

以下是R本身的混合方法的几个例子:

i)该mapply函数使用这两种方法...MoreArgs列表:

> args(mapply)
function (FUN, ..., MoreArgs = NULL, SIMPLIFY = TRUE, USE.NAMES = TRUE) 
NULL
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)


r2e*_*ans 14

  1. 为什么grep以前出错sum

    看到它sum更适应其论点:

    X <- c(1:5, NA, 6:10)
    sum(X, na.rm = TRUE, value = TRUE)
    ## [1] 56
    
    Run Code Online (Sandbox Code Playgroud)

    它没有失败,因为它不关心其他命名参数,所以value = TRUE简化为TRUE哪个总和为1.顺便说一下:

    sum(X, na.rm = TRUE)
    ## [1] 55
    
    Run Code Online (Sandbox Code Playgroud)
  2. 如何拆分...到不同的功能?

    一种方法(非常容易出错)是寻找目标函数的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])))
    }
    
    Run Code Online (Sandbox Code Playgroud)

    只要函数使用的参数没有正确报告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"         "..."         ""           
    
    Run Code Online (Sandbox Code Playgroud)

    在这种情况下,您可以替换相应的S3函数.因此,我没有一个通用的解决方案(虽然我不知道它确实存在或不存在).