R语言封装dplyr::select时统一处理字符串与裸列名的方法
问题解答
你要的替代convert_to_env_variable的实际函数可使用rlang::sym(单字段场景),不过更推荐直接简化逻辑,无需分支判断,就能同时兼容裸列名、字符串列名、甚至存储了列名的变量传参:
最优简化实现
library(dplyr) select_col_desired <- function(df, chosen_col) { # ensym自动兼容裸名、字符串、存储字符串的变量三种输入 col <- rlang::ensym(chosen_col) df %>% select(!!col) }
如果需要支持选择多列,改成ensyms和复数冒号运算符即可:
select_cols_desired <- function(df, ...) { cols <- rlang::ensyms(...) df %>% select(!!!cols) }
原实现问题说明
你原来写的is.character(enquo(chosen_col))判断逻辑是错误的:enquo()返回的是quosure封装对象,对它直接调用is.character()永远返回FALSE,之前的代码能正常运行只是因为dplyr::select原生支持直接传入字符串字面量,但如果遇到把列名存在变量里再传参的场景就会失效:
# 原实现无法处理这类场景 target_col <- "mpg" mtcars %>% select_col(target_col) # 会报错找不到target_col列
验证兼容效果
三种常见传参方式都可以正常运行:
# 1. 裸列名传参 mtcars %>% select_col_desired(mpg) %>% head(2) #> mpg #> Mazda RX4 21 #> Mazda RX4 Wag 21 # 2. 字符串字面量传参 mtcars %>% select_col_desired("mpg") %>% head(2) #> mpg #> Mazda RX4 21 #> Mazda RX4 Wag 21 # 3. 存储列名的变量传参 target_col <- "mpg" mtcars %>% select_col_desired(target_col) %>% head(2) #> mpg #> Mazda RX4 21 #> Mazda RX4 Wag 21
保留分支结构的修正写法
如果一定要保留你写的if分支结构,替代convert_to_env_variable的代码是rlang::sym(chosen_col),修正后的分支写法如下:
select_col_desired <- function(df, chosen_col) { # 注意修正判断逻辑,要先取出quosure内的内容再判断类型 if(is.character(rlang::eval_tidy(enquo(chosen_col)))){ chosen_col <- rlang::sym(chosen_col) } df %>% select({{ chosen_col }}) }
内容的提问来源于stack exchange,提问作者Greg
相关产品推荐
相关产品推荐

