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
函数调用,我会在控制台输入它然后评估它的方式。
我篡改了 substitute
、lazyeval
、bquote
的替代方法,但我不太了解它们的真正作用,因此无法让它们发挥作用。
你能帮我找到一种更好的方法来构造调用并随后对其进行评估吗?
更新 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
我经常需要在另一个函数中创建一个函数调用,然后对其进行求值。我倾向于使用 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
函数调用,我会在控制台输入它然后评估它的方式。
我篡改了 substitute
、lazyeval
、bquote
的替代方法,但我不太了解它们的真正作用,因此无法让它们发挥作用。
你能帮我找到一种更好的方法来构造调用并随后对其进行评估吗?
更新 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