【问题标题】:Use character string as function argument使用字符串作为函数参数
【发布时间】:2011-12-11 19:49:25
【问题描述】:

我确定这很简单,但我找不到解决方案... 我想使用一个包含字符串的变量作为函数的参数。

x <- c(1:10)
myoptions <- "trim=0, na.rm=FALSE"

现在,像

foo <- mean(x, myoptions)

应该和

一样
foo <- mean(x, trim=0, na.rm=FALSE)

提前致谢!

【问题讨论】:

  • 虽然我确信有人会为此发布解决方案,但我认为这样做有点不寻常。你想多介绍一下你真正想做的事情吗?
  • 我有一个由外部程序编写的 CSV 文件,其中每行包含一串参数。这应该用作 svm() 函数的输入,以构建具有不同设置的 SVM 模型。所以 CSV 文件的第一行是“cost=1, gamma=0.001”,第二行是“cost=5, gamma=0.001”,以此类推。我想遍历 CSV 文件的所有行。
  • 如果您粘贴 CSV 文件的前几行,您可能会得到更好的答案。

标签: string r function


【解决方案1】:

您可以使用evalparse

foo <- eval(parse(text = paste("mean(x,", myoptions, ")")))

【讨论】:

  • 非常感谢,这行得通!也许我的想法是错误的——所以没有办法像foo &lt;- mean(x, take.this.as.arguments(myoptions)) 那样做?
  • @Kilian 这很难,也许不可能。
  • 我怀疑@koshke 不会再说这更难了。我认为csgillespie的答案是正确的。
【解决方案2】:

使用do.call 是一种更自然的方式来做你想做的事。例如,

R> l[["trim"]] = 0
R> l[["na.rm"]] = FALSE
R> l[["x"]] = 1:10
##Or l <- list(trim = 0, na.rm = FALSE, x = 1:10)
R> do.call(mean, l)
 [1] 5.5

如果出于某种原因您真的想使用myoptions 字符串,您可以随时使用strsplit 将其强制转换为列表形式。例如,

R> y = "trim=0, na.rm=FALSE"
R> strsplit(y, ", ")
[[1]]
[1] "trim=0"      "na.rm=FALSE" 
R> strsplit(y, ", ")[[1]][1]
[1] "trim=0"

【讨论】:

  • 不使用l &lt;- list(trim = 0, na.rm = FALSE, x = 1:10)有什么原因吗?
  • 我投票支持第二种方法:do.callstrsplit
  • @DWin 为什么你更喜欢do.call/strsplit 而不是eval/parse?我知道有些人不喜欢使用eval/parse。有什么理由吗?谢谢。
  • 我只是想听从我的大多数人的建议。既然我认为你也是我最好的人之一,我承认我很矛盾。
  • 我同意do.call 在大多数情况下更干净。但是在这里,由于参数(即 R 表达式)作为字符串提供,parse 可能更干净。所以它认为这是根据具体情况而定的。
【解决方案3】:

这是第三个答案,两者都使用parsealistdo.call。我对这个新答案的动机是在参数从客户端作为字符交互传递的情况下。然后我想,没有好办法不使用parse。建议使用strsplit 的解决方案,无法理解逗号, 表示下一个参数或参数中的下一个参数的上下文。 strsplit 不理解上下文,因为 strsplit 不是解析器。

这里的参数可以传递为"a=c(2,4), b=3,5"list("c(a=(2,4)","b=3","5")

#' convert and evaluate a list of char args to a list of arguments
#'
#' @param listOfCharArgs a list of chars 
#'
#' @return
#' @export
#'
#' @examples
#' myCharArgs = list('x=c(1:3,NA)',"trim=0","TRUE")
#' myArgs = callMeMaybe(myCharArgs)
#' do.call(mean,myArgs)
callMeMaybe2 = function(listOfCharArgs) {
  CharArgs = unlist(listOfCharArgs)
  if(is.null(CharArgs)) return(alist())
    .out = eval(parse(text = paste0("alist(",
      paste(parse(text=CharArgs),collapse = ","),")")))
}

myCharArgs = list('x=c(1:3,NA)',"trim=0","TRUE")
myArgs = callMeMaybe2(myCharArgs)
do.call(mean,myArgs)
 [1] 2

【讨论】:

  • 我的第一个答案是相当不安全的,因为用户可能有例如“退出('no')”或未评估的内容
【解决方案4】:

使用所有do.callevalparse(结合kohske 和csgillespie 的答案,以及WoDoSc's answer to 'Pass a comma separated string as a list'):

x <- c(1:10)
myoptions <- "trim = 0, na.rm = FALSE"

do.call(
  what = mean,
  args = append(list(x = x), eval(parse(text = paste0("list(", myoptions, ")"))))
)

这种解决方案在更复杂的情况下可以很有弹性,如下所示。

myfn <- function(x, y = 0, z = 0, ...) {
  print(paste("x:", x))
  print(paste("y:", y))
  print(paste("z:", z))
  if (length(list(...)) > 0) {
    print("other:")
    print(list(...))
  }
}

myextraargs <- paste(
  "y = c(11, 14), z = 47,",
  "t = data.frame(p = c('apple', 'plum'), j = c(7, 2), k = c(3, 21))"
)

do.call(
  what = myfn,
  args = append(
    list(x = 7),
    eval(parse(text = paste0("list(", myextraargs, ")")))
  )
)

结果:

[1] "x: 7"
[1] "y: 11" "y: 14"
[1] "z: 47"
[1] "other:"
$t
      p j  k
1 apple 7  3
2  plum 2 21

...和...

myextraargs <- NULL

do.call(
  what = myfn,
  args = append(
    list(x = 7),
    eval(parse(text = paste0("list(", myextraargs, ")")))
  )
)

结果

[1] "x: 7"
[1] "y: 0"
[1] "z: 0"

【讨论】:

    最近更新 更多