如何将多个带任意参数的dplyr方法作为函数参数传入?
如何在R函数中传入多个带任意参数的dplyr方法
要实现传入任意数量、各带独立参数的dplyr方法,最简洁的思路是将每个方法与其参数打包成列表元素,再在函数内部依次执行这些操作。以下是几种可行方案:
方案1:用列表传递操作序列 + purrr::reduce
将每个dplyr方法和对应的参数封装成子列表,通过主列表传入函数,再用purrr::reduce实现链式调用:
library(dplyr) library(purrr) apply_dplyr_ops <- function(input_data, ops) { input_data %>% reduce(ops, .f = function(data, op) { # 用do.call将数据和参数传递给目标方法 do.call(op$fn, c(list(data), op$args)) }) }
测试示例
# 构造测试数据框 dframe <- data.frame( start = c(1,1,1,2,2,3,3,3,3), middle = sample(1:9), end = c(1,2,3,1,2,1,2,3,4) ) # 定义两个操作:先筛选再选择列 my_ops <- list( list(fn = dplyr::filter, args = list(start == 1, end == 2)), list(fn = dplyr::select, args = list(all_of(c("start", "middle")))) ) # 执行操作 result <- apply_dplyr_ops(dframe, my_ops) print(result)
方案2:用rlang::exec简化调用
rlang::exec是do.call的替代方案,语法更简洁,支持!!!展开参数列表:
library(dplyr) library(purrr) library(rlang) apply_dplyr_ops_exec <- function(input_data, ops) { input_data %>% reduce(ops, .f = function(data, op) { exec(op$fn, data, !!!op$args) }) } # 调用方式和方案1完全一致 result_exec <- apply_dplyr_ops_exec(dframe, my_ops)
方案3:用可变参数直接传递操作
如果不想预先定义操作列表,可以用...直接接收多个打包好的操作,调用时更直观:
apply_dplyr_ops_dots <- function(input_data, ...) { ops <- list(...) input_data %>% reduce(ops, .f = function(data, op) { exec(op$fn, data, !!!op$args) }) } # 直接在调用时传入每个操作 result_dots <- apply_dplyr_ops_dots( dframe, list(fn = dplyr::filter, args = list(start == 1, end == 2)), list(fn = dplyr::select, args = list(all_of(c("start", "middle")))) )
注意事项
你之前用do.call失败,大概率是没把输入数据作为第一个参数传入参数列表。do.call要求第二个参数是包含所有函数参数的列表,所以必须把data放在参数列表的首位(c(list(data), op$args)),才能让dplyr方法正确识别数据输入。
内容的提问来源于stack exchange,提问作者Matthew Cassell
相关产品推荐
相关产品推荐

