R:以编程方式创建函数调用

R: programmatically create a function call

我经常需要在另一个函数中创建一个函数调用,然后对其进行求值。我倾向于使用 eval(parse(text = "what_needs_to_be_done")) 为此,使用 paste0() 构建的文本。但是,这并不是一个好的方法。这是一个例子:

select_data <- function(x, A = NULL, B = NULL, C = NULL) {
  kall <- as.list(match.call())
  vars <- names(kall)[names(kall) %in% c("A", "B", "C")]
  selection_criteria <- paste0(vars,  " == ", kall[vars], collapse = ", ")
  txt <- paste0("dplyr::filter(x, ", selection_criteria, ")")
  res <- eval(parse(text = txt))
  return(res)
}   

DF <- data.frame(A = c(1,1,2,2,3,3), B = c(1,2,1,2,1,2), C = c(1,1,1,2,2,2))
select_data(DF, A = 2, C = 2)

这只是一个例子,大多数情况下要构建的功能更加复杂和广泛。但是,该示例显示了一般问题。我现在做的是首先 paste0 函数调用,我会在控制台输入它然后评估它的方式。

我篡改了 substitutelazyevalbquote 的替代方法,但我不太了解它们的真正作用,因此无法让它们发挥作用。

你能帮我找到一种更好的方法来构造调用并随后对其进行评估吗?

更新 4.29.17 -- 即将发布的 dplyr 0.6.0 将解决这些问题。新的答案已添加到以下问题。有关使用 dplyr 编程的更多信息,see this vignette


你的想法是对的。您可以使用 ?filter_ 和点参数 ...:

稍微缩短代码
select_data <- function(x, ...) {
  kall <- list(...)
  filter_(.data=x, paste0(names(kall), "==", unlist(kall), collapse="&"))
}
select_data(DF, A = 2, C = 2)
#   A B C
# 1 2 2 2

更新

使用 dplyr 进行编程即使对于中级编码员来说也是非常具有挑战性的。作者承认,非标准评估的优势伴随着函数式编程的困难成本。有许多 SO 用户 运行 遇到了同样的问题:

standard evaluation in dplyr

dplyr function does not work

Major dplyr functions in a function

已采取措施解决这些问题。有一个vignette to outline the basic fixes。不过,以我的拙见,小插图缺乏对函数式编程的解释。没有一个函数是作为示例编写的。它也没有解决通常出现的任何混淆示例。希望随着修复 NSE 的呼声越来越高,我们最终可能会得到足够的回应。

作为非标准评估可能导致编程混乱的最后一个例子,我曾尝试为该用户制定解决方案一段时间但无济于事。它只是要求以编程方式使用 summarise

Sub-function in grouping function using dplyr