>我有一个这样的函数来检索项目。
fetchItem <- function(name, ..., FUN)
- 名称:文件名的字符串
- ...:路径或URL等的零到许多部分,它在幕后构建了完整的路径(无需过多详细介绍,这对于消费者来说非常重要,他们可以向它扔任何东西,它只是"为他们做这一切"(
- FUN:[可选]为您想要如何读取它定义一个"读取器"函数(JSON 与 CSV 等的不同读取器函数处理并按照他们想要的方式返回它(。
到目前为止一切顺利,效果很好。但是现在我有一个请求,他们希望能够将其他参数传递给 FUN 阅读器(基本上是选项,例如它是否有标题行,如果它使用某种时髦的分隔符之类的东西,有一堆他们想要支持(。如果我能弄清楚如何通过它传递它们,读者将能够处理这些额外的参数,但我是 R 的新手,并且正在努力解决它如何链接在一起的语法。
为了说明我上面最后一条评论中的观点,这样的事情怎么样?
do_something <- function(x, ..., FUN = NULL) {
if (is.null(FUN)) print(x)
# Get all additional arguments
args <- list(...)
# Match additional arguments that are allowed for FUN
args_for_FUN <- NULL
if (length(args) > 0) {
allowed_args_for_FUN = c("na.rm")
# Allow for partial matching
names(args) <- sapply(names(args), function(arg)
match.arg(arg, allowed_args_for_FUN))
args_for_FUN <- args[names(args) %in% allowed_args_for_FUN]
}
# Execute FUN (if given)
if (is.function(FUN)) do.call(FUN, c(list(x = x), args_for_FUN))
}
让我们做一些测试用例:
# Case 1: No FUN, no additional args
do_something(1:10)
# [1] 1 2 3 4 5 6 7 8 9 10
# Case 2: With FUN, no additional args
do_something(1:10, FUN = mean)
#[1] 5.5
# Case 3: With FUN, no additional args
do_something(c(1:10, NA), FUN = mean)
#[1] NA
# Case 4: With FUN, with an additional arg for FUN
do_something(c(1:10, NA), na.rm = T, FUN = mean)
#[1] 5.5
虽然我可以想象有时这可能是有问题的,但一种技术可能是将所有未命名的参数用于一个目的,并要求所有FUN
参数都显式命名。
过度简化您对...
的使用只是连接到文件路径:
fetchItem <- function(name, ..., FUN) {
dots <- list(...)
nms <- names(dots)
args1 <- is.null(nms) | nms == ""
list(
nofunargs = c(name = name, dots[args1]),
funargs = dots[!args1]
)
}
str( fetchItem("foo", "bar", FUN = read.csv, stringsAsFactors = FALSE, header = TRUE) )
# List of 2
# $ nofunargs:List of 2
# ..$ name: chr "foo"
# ..$ : chr "bar"
# $ funargs :List of 2
# ..$ stringsAsFactors: logi FALSE
# ..$ header : logi TRUE
另一种选择有点脆弱:FUN=
(必须命名(之后的参数被传递给FUN
,而不是第一个目的。
fetchItem2 <- function(name, ..., FUN) {
args <- as.list(sys.call())[-1]
nms <- names(args)
FUNind <- which(nms == "FUN")
if (!length(FUNind)) FUNind <- length(nms) + 1L
list(
nofunargs = args[ seq_len(FUNind - 1L) ],
funargs = args[ -seq_len(FUNind) ]
)
}
str( fetchItem2("foo", "bar", FUN = read.csv, stringsAsFactors = FALSE, header = TRUE, name = "othername") )
# List of 2
# $ nofunargs:List of 2
# ..$ : chr "foo"
# ..$ : chr "bar"
# $ funargs :List of 3
# ..$ stringsAsFactors: logi FALSE
# ..$ header : logi TRUE
# ..$ name : chr "othername"