如何匹配 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 数组:

显然,这可以用 4 个 if 语句(每个组合一个)来处理,但如果我们有更多组合(如我打开的 choose_procedure() 示例),编程将变得非常困难。

所以我有两个问题:

  1. 我正在寻找可以扩展到潜在任何 n × n 数组的设置。
  2. 事实上,也许有一种方法可以泛化到超过 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 创建