r - 将函数列表作为参数传递的最佳方法是什么?

标签 r function parameter-passing

我正在寻找有关将函数列表作为参数传递的最佳编码方式的建议。

我想做什么:

我想将一个列表作为参数传递给一个函数以将它们应用于特定的输入。并根据这些给出输出名称。

一个“可重现”的例子

input = 1:5

要传递的函数是 mean , min
预期调用:
foo(input, something_i_ask_help_for)

预期输出:
list(mean = 3, min = 1)

如果不是很清楚,请参阅我的两个解决方案以进行说明。

解决方案1:将函数作为参数传递
foo <- function(input, funs){
  # Initialize output
  output = list()

  # Compute output
  for (fun_name in names(funs)){
    # For each function I calculate it and store it in output
    output[fun_name] = funs[[fun_name]](input)
  }

  return(output)
}

foo(1:5, list(mean=mean, min=min))

我不喜欢这种方法的地方在于我们不能通过以下方式调用它:foo(1:5, list(mean, min)) .

解决方案2:将函数名称作为参数传递并使用 get
foo2 <- function(input, funs){
  # Initialize output
  output = list()

  # Compute output
  for (fun in funs){
    # For each function I calculate it and store it in output
    output[fun] = get(fun)(input)
  }

  return(output)
}
foo2(1:5, c("mean", "min"))

我不喜欢这种方法的地方在于我们并没有真正将函数对象作为参数传递。

我的问题:

两种方式都有效,但我不太确定该选择哪一种。

你能帮我吗:
  • 告诉我哪个最好?
  • 每种方法的优点和默认值是什么?
  • 是否有另一种(更好的)方法

  • 如果您需要更多信息,请随时询问。

    谢谢!

    最佳答案

    简化有问题的解决方案

    问题中的第一个解决方案要求为列表命名,第二个解决方案要求函数具有作为字符串传递的名称。可以使用以下简化来实现这两个用户界面。请注意,我们添加了 envir论据 foo2以确保按预期进行函数名称查找。其中第一个看起来更清晰,但如果这些功能是交互使用的并且需要较少的输入,那么第二个就不需要指定名称。

    foo1 <- function(input, funs) Map(function(f) f(input), funs)
    foo1(1:5, list(min = min, max = max)) # test
    
    foo2 <- function(input, nms, envir = parent.frame()) {
        Map(function(nm) do.call(nm, list(input), envir = envir), setNames(nms, nms))
    }
    foo2(1:5, list("min", "max")) # test
    

    或者,我们可以构建 foo2foo1 :
    foo2a <- function(input, funs, envir = parent.frame()) {
        foo1(input, mget(unlist(funs), envir = envir, inherit = TRUE))
    }
    foo2a(1:5, list("min", "max")) # test
    

    或基于传递包含函数名称的公式的用户界面,因为公式已经包含环境的概念:
    foo2b <- function(input, fo) foo2(input, all.vars(fo), envir = environment(fo))
    foo2b(1:5, ~ min + max) # test
    

    传递函数本身时的可选名称

    然而,问题表明,最好是
  • 函数本身被传递
  • 名称是可选的

  • 为了合并这些功能,以下允许列表具有名称或不具有名称或混合名称。如果列表元素没有名称,则使用定义函数的表达式(通常是它的名称)。

    我们可以从列表的名称中导出名称,或者当缺少名称时,我们可以使用函数名称本身,或者如果函数是匿名的,因此作为其定义给出,则名称可以是定义函数的表达式。

    关键是用match.call并将其拆开。我们保证funs是一个列表,以防它被指定为字符向量。 match.fun将解释函数和字符串命名函数并在父框架中查找它们,因此我们使用 for循环而不是 Maplapply为了不生成新的函数作用域。
    foo3 <- function(input, funs) {
      cl <- match.call()[[3]][-1]
      nms <- names(cl)
      if (is.null(nms)) nms <- as.character(cl)
      else nms[nms == ""] <- as.character(cl)[nms == ""]
      funs <- as.list(funs)
      for(i in seq_along(funs)) funs[[i]] <- match.fun(funs[[i]])(input)
      setNames(funs, nms)
    }
    
    foo3(1:5, list(mean = mean, min = "min", sd, function(x) x^2))
    

    给予:
    $mean
    [1] 3
    
    $min
    [1] 1
    
    $sd
    [1] 1.581139
    
    $`function(x) x^2`
    [1]  1  4  9 16 25
    

    关于r - 将函数列表作为参数传递的最佳方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48010576/

    相关文章:

    javascript - 动态创建的js脚本onClick函数变量未绑定(bind)在当前值

    ios - 从自定义可编辑的 UITableViewCell 更新另一个字符串 - 在 swift 中通过引用传递?

    java - 参数可以是比传递的参数更通用的类吗?

    css - 增量幻灯片不适用于两列布局

    r - 创建一个不包含重复整数的所有九位数字的矩阵

    r - ggplot2中的条形图,宽度为变量,条形之间的间距均匀

    c - 在函数中打开二进制文件?请参阅代码 :

    javascript - 在函数调用时将数组解析为字符串

    c++ - 将具有派生模板的对象传递给接受具有基本模板的对象的函数

    r - R 中 shell 命令的并行计算