如何匹配 R 中函数参数的多种组合?
How to match many combinations of function arguments in R?
我们可以创建一个二维数组来匹配两个函数参数的组合吗?
例如,如果我编写一个带有 1 个参数的函数(除了数据输入参数):
choose_procedure <- function(x, what_to_do) {
switch(what_to_do,
"mean" = {...}, # mean(x) or mean(x, na.rm = TRUE) or weighted.mean(x)
"median" = {...}, # median(x)
"square" = {...}, # x * x or x ^ 2
"unique" = {...}, # unique(x)
"log" = {...} # log(x) or log10(x)
)
}
我添加了内联注释以暗示每个 what_to_do
输入可以有多个选择。
当what_to_do
= "mean"
时,应该是mean(x, na.rm = TRUE)
还是mean(x, na.rm = FALSE)
?
同样,当what_to_do
= "log"
时,应该是log(x)
还是log10(x)
?等等
为了解决这个问题,我想向 choose_procedure()
引入另一个参数,称为 "scenario"
。因此,如果对 choose_procedure()
的调用是:
choose_procedure(x = mtcars$mpg, what_to_do = "log", scenario = "A")
然后执行log(mtcars$mpg)
。
但是如果调用是
choose_procedure(x = mtcars$mpg, what_to_do = "log", scenario = "B")
然后会执行log10(mtcars$mpg)
.
仅包含 "log"
和 "scenario"
的示例描述了一个 2x2 数组:
"what_to_do"
有 2 个选项:log()
或 log10()
"scenario"
有两个选项:"A"
或"B"
显然,这可以用 4 个 if 语句(每个组合一个)来处理,但如果我们有更多组合(如我打开的 choose_procedure()
示例),编程将变得非常困难。
所以我有两个问题:
- 我正在寻找可以扩展到潜在任何 n × n 数组的设置。
- 事实上,也许有一种方法可以泛化到超过 n × n?例如,如果我们有 3 个参数:
"what_do_to"
、"scenario"
、"sub_scenario"
。等等
choose_procedure <- function(x, FUN, ...){
if(...length()) FUN(x, ...)
else FUN(x)
}
x <- c(1,3,5,NA, 10)
choose_procedure(x, mean)
[1] NA
choose_procedure(x, mean, na.rm = TRUE)
[1] 4.75
choose_procedure(x, log)
[1] 0.000000 1.098612 1.609438 NA 2.302585
choose_procedure(x, log10)
[1] 0.0000000 0.4771213 0.6989700 NA 1.0000000
这是有很多方法可以解决问题的事情之一,最好的方法很可能取决于您实际想要使用它的上下文。但是,在您概述的情况下,这是我的处理方式:
choose_procedure <- function(x, ...) {
# Define a table of options
choices <- tibble::tribble(
~what_to_do, ~scenario, ~result,
"mean", "A", mean,
"mean", "B", ~mean(., na.rm = TRUE),
"mean", "C", weighted.mean,
"median", "A", median,
"square", "A", ~. * .,
"square", "B", ~. ^ 2,
"unique", "A", unique,
"log", "A", log,
"log", "B", log10
)
# Filter the table down to the desired option
choice <- dplyr::filter(choices, ...)
# Stop if no options available
if (nrow(choice) == 0) {
stop("No such option available")
}
# Warn if multiple options available, and use first
if (nrow(choice) > 1) {
choice <- head(choices, 1)
warning("More than one option available, using first scenario")
}
# Transform any purrr-style lambda functions to normal functions
fun <- rlang::as_function(choice$result[[1]])
# Perform the calculation
fun(x)
}
choose_procedure(x = mtcars$mpg, what_to_do == "log", scenario == "B")
#> [1] 1.322219 1.322219 1.357935 1.330414 1.271842 1.257679 1.155336 1.387390
#> [9] 1.357935 1.283301 1.250420 1.214844 1.238046 1.181844 1.017033 1.017033
#> [17] 1.167317 1.510545 1.482874 1.530200 1.332438 1.190332 1.181844 1.123852
#> [25] 1.283301 1.436163 1.414973 1.482874 1.198657 1.294466 1.176091 1.330414
由 reprex package (v2.0.0)
于 2021-10-25 创建
我们可以创建一个二维数组来匹配两个函数参数的组合吗?
例如,如果我编写一个带有 1 个参数的函数(除了数据输入参数):
choose_procedure <- function(x, what_to_do) {
switch(what_to_do,
"mean" = {...}, # mean(x) or mean(x, na.rm = TRUE) or weighted.mean(x)
"median" = {...}, # median(x)
"square" = {...}, # x * x or x ^ 2
"unique" = {...}, # unique(x)
"log" = {...} # log(x) or log10(x)
)
}
我添加了内联注释以暗示每个 what_to_do
输入可以有多个选择。
当what_to_do
= "mean"
时,应该是mean(x, na.rm = TRUE)
还是mean(x, na.rm = FALSE)
?
同样,当what_to_do
= "log"
时,应该是log(x)
还是log10(x)
?等等
为了解决这个问题,我想向 choose_procedure()
引入另一个参数,称为 "scenario"
。因此,如果对 choose_procedure()
的调用是:
choose_procedure(x = mtcars$mpg, what_to_do = "log", scenario = "A")
然后执行log(mtcars$mpg)
。
但是如果调用是
choose_procedure(x = mtcars$mpg, what_to_do = "log", scenario = "B")
然后会执行log10(mtcars$mpg)
.
仅包含 "log"
和 "scenario"
的示例描述了一个 2x2 数组:
"what_to_do"
有 2 个选项:log()
或log10()
"scenario"
有两个选项:"A"
或"B"
显然,这可以用 4 个 if 语句(每个组合一个)来处理,但如果我们有更多组合(如我打开的 choose_procedure()
示例),编程将变得非常困难。
所以我有两个问题:
- 我正在寻找可以扩展到潜在任何 n × n 数组的设置。
- 事实上,也许有一种方法可以泛化到超过 n × n?例如,如果我们有 3 个参数:
"what_do_to"
、"scenario"
、"sub_scenario"
。等等
choose_procedure <- function(x, FUN, ...){
if(...length()) FUN(x, ...)
else FUN(x)
}
x <- c(1,3,5,NA, 10)
choose_procedure(x, mean)
[1] NA
choose_procedure(x, mean, na.rm = TRUE)
[1] 4.75
choose_procedure(x, log)
[1] 0.000000 1.098612 1.609438 NA 2.302585
choose_procedure(x, log10)
[1] 0.0000000 0.4771213 0.6989700 NA 1.0000000
这是有很多方法可以解决问题的事情之一,最好的方法很可能取决于您实际想要使用它的上下文。但是,在您概述的情况下,这是我的处理方式:
choose_procedure <- function(x, ...) {
# Define a table of options
choices <- tibble::tribble(
~what_to_do, ~scenario, ~result,
"mean", "A", mean,
"mean", "B", ~mean(., na.rm = TRUE),
"mean", "C", weighted.mean,
"median", "A", median,
"square", "A", ~. * .,
"square", "B", ~. ^ 2,
"unique", "A", unique,
"log", "A", log,
"log", "B", log10
)
# Filter the table down to the desired option
choice <- dplyr::filter(choices, ...)
# Stop if no options available
if (nrow(choice) == 0) {
stop("No such option available")
}
# Warn if multiple options available, and use first
if (nrow(choice) > 1) {
choice <- head(choices, 1)
warning("More than one option available, using first scenario")
}
# Transform any purrr-style lambda functions to normal functions
fun <- rlang::as_function(choice$result[[1]])
# Perform the calculation
fun(x)
}
choose_procedure(x = mtcars$mpg, what_to_do == "log", scenario == "B")
#> [1] 1.322219 1.322219 1.357935 1.330414 1.271842 1.257679 1.155336 1.387390
#> [9] 1.357935 1.283301 1.250420 1.214844 1.238046 1.181844 1.017033 1.017033
#> [17] 1.167317 1.510545 1.482874 1.530200 1.332438 1.190332 1.181844 1.123852
#> [25] 1.283301 1.436163 1.414973 1.482874 1.198657 1.294466 1.176091 1.330414
由 reprex package (v2.0.0)
于 2021-10-25 创建