R&quosures - 如何获取作为函数参数传递的向量中包含的符号名称?
R & quosures - How to get names of symbols contained in a vector passed as function argument?
我想编写一个 R 函数 arg2str
,其中 returns 作为参数提供的符号的名称(即字符串向量)。
对于最简单的情况,我只有一个输入符号:
library ("rlang")
arg2str.v0 <- function (arg) rlang::quo_name (enquo (arg))
arg2str.v0 (a)
## [1] "a"
如果我有多个符号,我可以使用三点结构:
arg2str.v1 <- function (...) sapply (enquos (...), rlang::quo_name)
arg2str.v1 (a, b, c)
##
## "a" "b" "c"
(补充问题:为什么在这种情况下显示的结果字符串向量带有初步换行符而不是初步 [1]
?)
但我实际上想处理符号向量。然而:
sym2str.v1 (c(a, b, c))
##
## "c(a, b, c)"
我该如何调整我的功能来做到这一点?
我的第一直觉是首先使用 sapply
引用参数向量中包含的符号(而不是引用参数向量本身),然后将 rlang::quo_name
应用于结果向量.但似乎参数向量中的符号是在 sapply
内评估的,然后在每个符号上调用 enquote
:
arg2str.v2 <- function (args) {
enquo_args <- sapply (args, enquo)
lapply (enquo_args, rlang::quo_name)
}
arg2str.v2 (c (a, b, c))
## Error in lapply(X = X, FUN = FUN, ...) : object 'a' not found
我不确定是否有您想要的矢量化 tidyeval 操作。你可以试试
f <- function(v) {
v <- rlang::quo_name(enquo(v))
gsub('^c\(|\s|\)$', '', v) %>%
strsplit(',') %>%
unlist
}
f(c(a, b, c))
#[1] "a" "b" "c"
这将适用于 a
、c(a)
或 c(a, b)
形式的输入,但它有点老套...
你的附带问题(为什么 arg2str.v1(a, b, c)
不在行首打印 "[1]"
)的答案是它 returns 一个命名向量,其名称为空字符串(例如与 set_names(c('a', 'b', 'c'), c('', '', ''))
的输出进行比较)。
使用 substitute
和 deparse
的一个可能的 hacky 答案:
arg2str.v3 <- function (args) {
strs <- sapply (substitute (args), deparse)
if (length (strs) > 1) { strs <- strs [-1] }
return (strs)
}
arg2str.v3 (c (a, b, c))
## [1] "a" "b" "c"
请注意,如果提供命名向量作为输入,它也会保留名称:
arg2str.v3 (c (n1 = a, n2 = b, n3 = c))
## n1 n2 n3
## "a" "b" "c"
使用 rlang 约定,这应该有效:
return_args <- function(args){
args_expr <- enexpr(args)
if(length(args_expr) == 1) {
args_vars <- as.list(args_expr)
} else {
args_vars <- as.list(args_expr)[-1]
}
sapply(args_vars, quo_name)
}
return_args(c(a, b, c))
[1] "a" "b" "c"
return_args(a)
[1] "a"
我想编写一个 R 函数 arg2str
,其中 returns 作为参数提供的符号的名称(即字符串向量)。
对于最简单的情况,我只有一个输入符号:
library ("rlang")
arg2str.v0 <- function (arg) rlang::quo_name (enquo (arg))
arg2str.v0 (a)
## [1] "a"
如果我有多个符号,我可以使用三点结构:
arg2str.v1 <- function (...) sapply (enquos (...), rlang::quo_name)
arg2str.v1 (a, b, c)
##
## "a" "b" "c"
(补充问题:为什么在这种情况下显示的结果字符串向量带有初步换行符而不是初步 [1]
?)
但我实际上想处理符号向量。然而:
sym2str.v1 (c(a, b, c))
##
## "c(a, b, c)"
我该如何调整我的功能来做到这一点?
我的第一直觉是首先使用 sapply
引用参数向量中包含的符号(而不是引用参数向量本身),然后将 rlang::quo_name
应用于结果向量.但似乎参数向量中的符号是在 sapply
内评估的,然后在每个符号上调用 enquote
:
arg2str.v2 <- function (args) {
enquo_args <- sapply (args, enquo)
lapply (enquo_args, rlang::quo_name)
}
arg2str.v2 (c (a, b, c))
## Error in lapply(X = X, FUN = FUN, ...) : object 'a' not found
我不确定是否有您想要的矢量化 tidyeval 操作。你可以试试
f <- function(v) {
v <- rlang::quo_name(enquo(v))
gsub('^c\(|\s|\)$', '', v) %>%
strsplit(',') %>%
unlist
}
f(c(a, b, c))
#[1] "a" "b" "c"
这将适用于 a
、c(a)
或 c(a, b)
形式的输入,但它有点老套...
你的附带问题(为什么 arg2str.v1(a, b, c)
不在行首打印 "[1]"
)的答案是它 returns 一个命名向量,其名称为空字符串(例如与 set_names(c('a', 'b', 'c'), c('', '', ''))
的输出进行比较)。
使用 substitute
和 deparse
的一个可能的 hacky 答案:
arg2str.v3 <- function (args) {
strs <- sapply (substitute (args), deparse)
if (length (strs) > 1) { strs <- strs [-1] }
return (strs)
}
arg2str.v3 (c (a, b, c))
## [1] "a" "b" "c"
请注意,如果提供命名向量作为输入,它也会保留名称:
arg2str.v3 (c (n1 = a, n2 = b, n3 = c))
## n1 n2 n3
## "a" "b" "c"
使用 rlang 约定,这应该有效:
return_args <- function(args){
args_expr <- enexpr(args)
if(length(args_expr) == 1) {
args_vars <- as.list(args_expr)
} else {
args_vars <- as.list(args_expr)[-1]
}
sapply(args_vars, quo_name)
}
return_args(c(a, b, c))
[1] "a" "b" "c"
return_args(a)
[1] "a"