使用Rlang:从quosures集合中提取.data代词对应的列名
从quosures中提取.data引用的列名(无需字符串解析)
嘿,这个问题我之前也碰到过——用rlang的quosures写汇总逻辑后,想快速提取用到的.data列名,不用字符串瞎凑,完全可以靠rlang的表达式工具搞定。
核心思路
你的quos里的.data[["ColumnName"]]本质是一个函数调用(调用的是[[函数,第一个参数是符号.data,第二个是列名字符串/符号)。我们可以拆解quo的表达式结构,递归查找所有这种调用,然后提取列名。
解决代码
首先写一个递归函数来遍历表达式,找出所有.data[[...]]的调用:
library(rlang) library(purrr) # 递归查找表达式中的.data[[...]]调用,返回列名 extract_data_cols <- function(expr) { # 匹配.data[[列名]]的结构 if (is_call(expr, "[[", n = 2) && is_symbol(expr[[1]], ".data")) { return(as.character(expr[[2]])) } # 如果是其他函数调用,递归遍历每个参数 if (is_call(expr)) { cols <- map(expr[-1], extract_data_cols) return(unlist(cols)) } # 非调用结构返回NULL NULL } # 包装一下,处理单个quo get_cols_from_quo <- function(quo) { extract_data_cols(quo_get_expr(quo)) }
然后把这个函数应用到你的my_quos列表上:
# 你的示例quos my_quos <- list2( "GenderD" = quo(length(.data[["TeamCode"]])), "GenderMaleN" = quo(.data[["S1IsMale"]]) ) # 提取所有列名,去重(如果有重复引用的话) result <- map(my_quos, get_cols_from_quo) %>% unlist() %>% unique() result #> [1] "TeamCode" "S1IsMale"
为什么不用is(..., "rlang_data_pronoun")?
你之前试的这个方法不行,是因为在quo的表达式阶段,.data只是一个普通的符号(symbol),只有当quo被求值的时候,它才会被转换成rlang_data_pronoun对象。所以我们要判断的是表达式里的符号名称是不是.data,用is_symbol(expr[[1]], ".data")就对了。
扩展说明
这个递归函数还能处理更复杂的嵌套情况,比如:
complex_quo <- quo(mean(.data[["Age"]], na.rm = TRUE) + sum(.data[["Score"]])) get_cols_from_quo(complex_quo) #> [1] "Age" "Score"
完全不用碰字符串解析,靠表达式结构分析,既可靠又符合rlang的语法设计。
内容的提问来源于stack exchange,提问作者Andrew Hill
相关产品推荐
相关产品推荐

