问题
I want to write an R function arg2str
that returns the names (that is a vector of strings) of the symbols that are fed as arguments.
For the most simple case, I only have one input symbol:
library ("rlang")
arg2str.v0 <- function (arg) rlang::quo_name (enquo (arg))
arg2str.v0 (a)
## [1] "a"
If I have multiple symbols, I can use the three-dots construct:
arg2str.v1 <- function (...) sapply (enquos (...), rlang::quo_name)
arg2str.v1 (a, b, c)
##
## "a" "b" "c"
(Subsidiary question: why is the resulting vector of strings displayed with a preliminary line break instead of a preliminary [1]
in this case?)
But I actually want to deal with vectors of symbols. Yet:
sym2str.v1 (c(a, b, c))
##
## "c(a, b, c)"
How do I tune my function to do so?
My first intuition was to first enquote the symbols contained in the argument vector by using sapply
(instead of enquoting the argument vector itself), then to apply rlang::quo_name
to the resulting vector of quosures. But it seems that the symbols in the argument vector are evaluated within sapply
before enquote
is called on each of them:
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
回答1:
Using rlang conventions, this should work:
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"
回答2:
I am not sure if there is a vectorised tidyeval operation for what you want. You can try
f <- function(v) {
v <- rlang::quo_name(enquo(v))
gsub('^c\\(|\\s|\\)$', '', v) %>%
strsplit(',') %>%
unlist
}
f(c(a, b, c))
#[1] "a" "b" "c"
which will work with inputs of the form a
, c(a)
or c(a, b)
but it's a bit hacky...
The answer to your side question (why arg2str.v1(a, b, c)
does not print the "[1]"
at the beginning of the line) is that it returns a named vector, whose names are empty strings (compare e.g. with the output of set_names(c('a', 'b', 'c'), c('', '', ''))
).
回答3:
One possible hacky answer using substitute
and deparse
:
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"
Note that it also preserves names if a named vector is provided as input:
arg2str.v3 (c (n1 = a, n2 = b, n3 = c))
## n1 n2 n3
## "a" "b" "c"
来源:https://stackoverflow.com/questions/52114227/r-quosures-how-to-get-names-of-symbols-contained-in-a-vector-passed-as-funct