【问题标题】:R & quosures - How to get names of symbols contained in a vector passed as function argument?R&quosures - 如何获取作为函数参数传递的向量中包含的符号名称?
【发布时间】:2019-02-06 09:56:06
【问题描述】:

我想编写一个 R 函数 arg2str,它返回作为参数输入的符号的名称(即字符串向量)。

对于最简单的情况,我只有一个输入符号:

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

【问题讨论】:

  • 试试这个:arg2str.v0 &lt;- Vectorize(arg2str.v0),希望对你有帮助。
  • 你试过你的代码了吗? @MrSmithGoesToWashington
  • 我当然做到了。
  • @MrSmithGoesToWashington,arg2str.v0 的矢量化版本出现类似错误,即:Error in FUN(X[[i]], ...) : object 'a' not found

标签: r quosure


【解决方案1】:

使用 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"

【讨论】:

    【解决方案2】:

    使用 substitutedeparse 的一个可能的 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"
    

    【讨论】:

      【解决方案3】:

      我不确定是否有你想要的矢量化 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"
      

      这将适用于 ac(a)c(a, b) 形式的输入,但它有点 hacky...

      您的附带问题的答案(为什么arg2str.v1(a, b, c) 不会在行首打印"[1]")是它返回一个命名向量,其名称是空字符串(例如与@987654327 的输出比较@)。

      【讨论】:

      • Hacky 确实,但它确实有效!然而,它不允许命名向量作为输入,例如f(c(n1=a, n2=b))(我在问题中没有指定的附加功能)。我想可以想出一个正则表达式来获取和保留这些名称。
      • 也感谢您对附带问题的回答。这很有意义!
      猜你喜欢
      • 2019-04-02
      • 1970-01-01
      • 1970-01-01
      • 2020-01-13
      • 2021-07-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-31
      相关资源
      最近更新 更多