向自定义R函数传递列名的两种方法:{{}}与.data[[]]对比
两种实现方式的专业术语
- 整洁求值(非标准求值):直接传递未加引号的列名(如
plot_dir(msleep, sleep_total, awake))的写法,属于tidyverse体系的整洁求值(Tidy Evaluation),是**非标准求值(NSE)**的一种具体实现。{{}}是整洁求值中的“注入运算符”,作用是捕获调用时传入的列名表达式,将其注入到ggplot、dplyr等支持整洁求值的函数中,无需将列名转为字符串。 - 标准求值(字符串引用):传递列名字符串(如
plot_str(msleep, 'sleep_total', 'awake'))的写法属于标准求值(SE)。.data[[x]]是tidyverse提供的.data代词,用于明确从数据框中按字符串索引提取列,是整洁求值体系中兼容标准输入的方式。
保持整洁求值语法的替代实现
如果想全程使用{{}}或整洁求值的语法处理列名列表,有两种常见方案:
方案1:接收未加引号的列名列表
让函数直接接收未加引号的列名组成的列表,内部用rlang::enexprs()捕获这些列名表达式,再结合purrr::map()遍历生成图表:
library(dplyr) library(ggplot2) library(purrr) library(rlang) data(msleep) plot_list_nse <- function(df, x, ylist) { # 捕获传入的列名表达式列表 y_exprs <- enexprs(ylist) # 遍历每个列名表达式生成图表 map(y_exprs, function(y) { ggplot(df, aes({{x}}, {{y}})) + geom_point() }) %>% # 给图表列表命名为列名字符串 set_names(map_chr(y_exprs, as_string)) } # 调用示例:直接传入未加引号的列名 plotout <- plot_list_nse(msleep, sleep_total, c(awake, sleep_rem))
方案2:兼容字符串列名列表
如果需要保留传入字符串列表的习惯,可先将字符串转换为符号(symbol),再用!!(bang-bang运算符)注入到表达式中,同样实现纯整洁求值的写法:
plot_list_str_nse <- function(df, x, ylist) { # 将字符串列表转换为符号列表 y_syms <- syms(ylist) map(y_syms, function(y) { ggplot(df, aes({{x}}, !!y)) + geom_point() }) %>% set_names(ylist) } # 调用示例:传入字符串列名列表 ylist <- c('awake', 'sleep_rem') plotout <- plot_list_str_nse(msleep, sleep_total, ylist)
说明:{{}}是!!enquo(x)的语法糖,enquo()用于捕获函数参数的表达式,!!用于将捕获或生成的表达式注入到目标函数中;syms()则是批量将字符串转换为符号的工具,让字符串列名可以参与整洁求值。
内容的提问来源于stack exchange,提问作者Jaken
相关产品推荐
相关产品推荐

