【问题标题】:r - Convert multiple function arguments to string vectorr - 将多个函数参数转换为字符串向量
【发布时间】:2014-05-16 19:07:33
【问题描述】:

我正在尝试编写一个函数:

myfunc <- function(df, out, ...) {   # ... = variables in a dataframe
df <- arrange(df, ...)               # plyr function that orders rows
out <- df[!duplicated(df[,c(...)]),] # remove duplicates
}

我不知道如何让 第三行 工作。 "..." 参数只需要转换成字符串向量,这样 !duplicated() 函数就可以工作了。

我知道 deparse(substitute(x)) 适用于 1 个参数:

> foo <- function(x) deparse(substitute(x))
> foo(bar)
[1] "bar"

但它不适用于多个参数。如何更改它以便多个参数起作用?

> foo <- function(...) deparse(substitute(...))
> foo(bar,goo,poo)
[1] "bar" "goo" "poo"

我也欢迎修改原始函数 (myfunc) 的其他解决方案,如果这样做更容易的话。谢谢。

【问题讨论】:

    标签: string r function


    【解决方案1】:

    deparse(substitute()) 不起作用,因为被替换的表达式仍然是一个表达式,并且期望各个元素是变量。诀窍是将省略号转换为列表,然后将其元素替换为表达式,最后解析表达式树中的每个元素:

    ellipsis_to_vector <- function(...) {
      # Convert to a list, but with the variables still as an expression
      args_as_expression = substitute(list(...))
      # Deparse each item in the expression, turning it into a char vector
      # Why the [-1]? Because the first element in the list expression is "list"! :-)
      args_as_char_vector = sapply(args_as_expression,deparse)[-1]  
      args_as_char_vector
    }
    ellipsis_to_vector(this, and, that)
    #> [1] "this" "and"  "that"
    ellipsis_to_vector(single)
    #> [1] "single"
    ellipsis_to_vector() # Works for empty ellipsis as well
    #> character(0)
    

    【讨论】:

    • 谢谢!这是一个更优雅的答案。
    【解决方案2】:

    我认为match.call 在这种情况下更适合您。观察

    foo <- function(df, ...) {
        mycall<-as.list(match.call())
        cols<-sapply(mycall[-(1:2)], deparse)
          df<-arrange(df, ...)
          df[!duplicated(df[, cols]),]
    }
    
    #test data    
    set.seed(15)
    dd<-data.frame(a=1:20,
        b=sample(1:50, 20, replace=T),
        c=sample(1:50, 20, replace=T)
    )
    dd <-rbind(dd, cbind(a=21:24, dd[9:12, 2:3])) # add dups
    dd <-dd[sample.int(nrow(dd)),]   #shuffle
    
    #try out function
    out<-foo(dd, b,c)
    out
    

    我离开了out,因为您确实应该在函数外部分配结果,否则在函数调用完成后对变量的更改会消失。

    【讨论】:

    • 我的方法类似,所以我不会作为答案发布:`cols &lt;- as.character(match.call(expand.dots = FALSE)[[3]]) 甚至cols &lt;- as.character(substitute(...()))
    • @TylerRinker ...() 部分很有趣。你知道... 的类是什么吗?是函数吗?
    最近更新 更多