寻求支持非标准计算(NSE)的dplyr::any_of()替代方案
优化dplyr可选列选择函数的实现
针对你需要的「支持可选列参数、自动校验列存在性、简化原有繁琐写法」的需求,这里提供两种简洁的实现方案:
方案一:动态构建选择参数列表
这种方式逻辑清晰,适合扩展更复杂的参数场景:
library(tidyverse) library(rlang) f <- function(data, x1, x2, gp = NULL) { # 捕获参数表达式 x1_expr <- enquo(x1) x2_expr <- enquo(x2) gp_expr <- enquo(gp) # 校验必选列是否存在 x1_name <- as_label(x1_expr) if (!x1_name %in% colnames(data)) { abort(glue::glue("列 '{x1_name}' 不存在于输入数据中")) } x2_name <- as_label(x2_expr) if (!x2_name %in% colnames(data)) { abort(glue::glue("列 '{x2_name}' 不存在于输入数据中")) } # 初始化选择参数列表 select_args <- exprs(x1 = !!x1_expr, x2 = !!x2_expr) # 处理可选的gp参数 if (!quo_is_null(gp_expr)) { gp_name <- as_label(gp_expr) if (!gp_name %in% colnames(data)) { abort(glue::glue("列 '{gp_name}' 不存在于输入数据中")) } select_args <- c(select_args, expr(gp = !!gp_expr)) } # 执行选择并返回列名 data %>% select(!!!select_args) %>% names() }
测试验证
# 传入所有参数 iris %>% f(Sepal.Length, Sepal.Width, Species) #> [1] "x1" "x2" "gp" # 不传入gp参数 iris %>% f(Sepal.Length, Sepal.Width) #> [1] "x1" "x2" # 传入不存在的列会触发错误 # iris %>% f(Sepal.Length, Sepal.Width, NotExist) #> Error in f(iris, Sepal.Length, Sepal.Width, NotExist) : #> 列 'NotExist' 不存在于输入数据中
方案二:紧凑的条件式选择写法
如果不需要复杂扩展,这种写法更简洁紧凑:
library(tidyverse) library(rlang) f <- function(data, x1, x2, gp = NULL) { x1 <- enquo(x1) x2 <- enquo(x2) gp <- enquo(gp) # 校验必选列 stopifnot(has_name(data, as_label(x1))) stopifnot(has_name(data, as_label(x2))) data %>% select( x1 = !!x1, x2 = !!x2, # 仅当gp被传入且列存在时添加选择项 !!if (!quo_is_null(gp)) { gp_name <- as_label(gp) if (!has_name(data, gp_name)) { abort(glue::glue("列 '{gp_name}' 不存在")) } expr(gp = !!gp) } ) %>% names() }
核心特性说明
- 无需手动将参数转为字符向量,直接利用
enquo捕获的表达式进行列选择 - 对所有传入的列(必选/可选)都做了存在性校验,不存在则抛出明确错误
- 自动适配「传入/不传入gp参数」两种场景,逻辑简洁直观
内容的提问来源于stack exchange,提问作者Dan Chaltiel
相关产品推荐
相关产品推荐

