使用 Rlang:在一组 quosures 中找到数据代词
Using Rlang: find the data pronoun in a set of quosures
我有一组正被用来使用 dplyr 生成汇总统计集的 quosures。
我想知道正在使用哪些数据列。
数据列以.data[["ColumnName"]]为前缀。
例如我们有:
my_quos <- rlang::list2(
"GenderD" = rlang::quo(length(.data[["TeamCode"]])),
"GenderMaleN" = rlang::quo(.data[["S1IsMale"]])
)
我已经开始通过使用 rlang::call_args() 将命令分解成它的组件来解决这个问题:
my_args_test <- rlang::call_args(my_quos[[1]])
str(my_args_test)
List of 1
$ : language .data[["TeamCode"]]
列都应该作为数据代词。有没有一种快速的方法来检查列表中的项目是否是数据代词?我试过:
is(my_args_test[[1]], "rlang_data_pronoun")
但这return是错误的。将字符串检查为以 .data[[ 开头的文本可能是我猜的一个选项(但我怀疑这更容易出错)。
还有没有办法直接return传递给数据代词的参数而不是解析字符串?换句话说,理想的目标是 return 我们的输出是:
c("TeamCode", "S1IsMale")
来自原文my_quos.
这可以分两步完成。首先,您想提取由您的 quosures 捕获的表达式并将它们转换为 Abstract Syntax Trees (ASTs).
## Recursively constructs Abstract Syntax Tree for a given expression
getAST <- function( ee ) { as.list(ee) %>% purrr::map_if(is.call, getAST) }
## Apply function to expressions captured by each quosure
asts <- purrr::map( my_quos, quo_get_expr ) %>% purrr::map( getAST )
str(asts)
# List of 2
# $ GenderD :List of 2
# ..$ : symbol length
# ..$ :List of 3
# .. ..$ : symbol [[
# .. ..$ : symbol .data
# .. ..$ : chr "TeamCode"
# $ GenderMaleN:List of 3
# ..$ : symbol [[
# ..$ : symbol .data
# ..$ : chr "S1IsMale"
从这里,我们看到模式匹配 .data[["somename"]]
是一个长度为 3 的列表,其中第一个条目是 [[
,第二个条目是 .data
,最后一个条目是您要提取的内容。让我们编写一个函数来识别此模式和 returns 识别后的第三个元素 (注意:此函数显示如何将项目与 .data
代词匹配,这是您的另一个问题):
## If the input matches .data[["name"]], returns "name". Otherwise, NULL
getName <- function( x )
{
if( is.list(x) && length(x) == 3 && ## It's a length-3 list
identical( x[[1]], quote(`[[`) ) && ## with [[ as the first element
identical( x[[2]], quote(.data) ) && ## .data as the second element
is.character(x[[3]]) ) return(x[[3]]) ## and a character string as 3rd
NULL
}
有了这个函数,第二步就是将它递归地应用到你的 AST 列表中,以提取使用的列名。
getNames <- function( aa ) {
purrr::keep(aa, is.list) %>%
purrr::map(getNames) %>% ## Recurse to any list descendants
c( getName(aa) ) %>% ## Append self to the result
unlist ## Return as character vector, not list
}
getNames(asts)
# GenderD GenderMaleN
# "TeamCode" "S1IsMale"
我有一组正被用来使用 dplyr 生成汇总统计集的 quosures。
我想知道正在使用哪些数据列。
数据列以.data[["ColumnName"]]为前缀。
例如我们有:
my_quos <- rlang::list2(
"GenderD" = rlang::quo(length(.data[["TeamCode"]])),
"GenderMaleN" = rlang::quo(.data[["S1IsMale"]])
)
我已经开始通过使用 rlang::call_args() 将命令分解成它的组件来解决这个问题:
my_args_test <- rlang::call_args(my_quos[[1]])
str(my_args_test)
List of 1
$ : language .data[["TeamCode"]]
列都应该作为数据代词。有没有一种快速的方法来检查列表中的项目是否是数据代词?我试过:
is(my_args_test[[1]], "rlang_data_pronoun")
但这return是错误的。将字符串检查为以 .data[[ 开头的文本可能是我猜的一个选项(但我怀疑这更容易出错)。
还有没有办法直接return传递给数据代词的参数而不是解析字符串?换句话说,理想的目标是 return 我们的输出是:
c("TeamCode", "S1IsMale")
来自原文my_quos.
这可以分两步完成。首先,您想提取由您的 quosures 捕获的表达式并将它们转换为 Abstract Syntax Trees (ASTs).
## Recursively constructs Abstract Syntax Tree for a given expression
getAST <- function( ee ) { as.list(ee) %>% purrr::map_if(is.call, getAST) }
## Apply function to expressions captured by each quosure
asts <- purrr::map( my_quos, quo_get_expr ) %>% purrr::map( getAST )
str(asts)
# List of 2
# $ GenderD :List of 2
# ..$ : symbol length
# ..$ :List of 3
# .. ..$ : symbol [[
# .. ..$ : symbol .data
# .. ..$ : chr "TeamCode"
# $ GenderMaleN:List of 3
# ..$ : symbol [[
# ..$ : symbol .data
# ..$ : chr "S1IsMale"
从这里,我们看到模式匹配 .data[["somename"]]
是一个长度为 3 的列表,其中第一个条目是 [[
,第二个条目是 .data
,最后一个条目是您要提取的内容。让我们编写一个函数来识别此模式和 returns 识别后的第三个元素 (注意:此函数显示如何将项目与 .data
代词匹配,这是您的另一个问题):
## If the input matches .data[["name"]], returns "name". Otherwise, NULL
getName <- function( x )
{
if( is.list(x) && length(x) == 3 && ## It's a length-3 list
identical( x[[1]], quote(`[[`) ) && ## with [[ as the first element
identical( x[[2]], quote(.data) ) && ## .data as the second element
is.character(x[[3]]) ) return(x[[3]]) ## and a character string as 3rd
NULL
}
有了这个函数,第二步就是将它递归地应用到你的 AST 列表中,以提取使用的列名。
getNames <- function( aa ) {
purrr::keep(aa, is.list) %>%
purrr::map(getNames) %>% ## Recurse to any list descendants
c( getName(aa) ) %>% ## Append self to the result
unlist ## Return as character vector, not list
}
getNames(asts)
# GenderD GenderMaleN
# "TeamCode" "S1IsMale"