0

第一次调用函数 f 有效,第二次无效。如何将字符串(“v”)传递给函数 f 以便函数按预期工作?

library(data.table)

f<-function(t,x) t[,deparse(substitute(x)),with=F]

dat<-data.table(v="a")

f(dat,v)
#    v
# 1: a

f(dat,eval(parse(text="v")))
# Error in `[.data.table`(t, , deparse(substitute(x)), with = F) : 
#   column(s) not found: eval(parse(text = "v")) 
4

1 回答 1

3

它不再是单线,但您可以测试您传入的内容:

library(data.table)
library(purrr)

dat <- data.table(v="a")

f <- function(dt, x) {

  # first, see if 'x' is a variable holding a string with a column name

  seval <- safely(eval)
  res <- seval(x, dt, parent.frame())

  # if it is, then get the value, otherwise substitute() it

  if ((!is.null(res$result)) && inherits(res$result, "character")) {
    y <- res$result
  } else {
    y <- substitute(x)
  }

  # if it's a bare name, then we deparse it, otherwise we turn
  # the string into name and then deparse it

  if (inherits(y, "name")) {
    y <- deparse(y) 
  } else if (inherits(y, "character")) {
    y <- deparse(as.name(x))
  }

  dt[, y, with=FALSE]

}

f(dat,v)
##    v
## 1: a

f(dat, "v")
##    v
## 1: a

V <- "v"
f(dat, V)
##    v
## 1: a

f(dat, VVV)
#> throws an Error

我将它从 切换t到 ,dt因为我不喜欢使用内置函数的名称(如t())作为变量名,除非我真的必须这样做。它可能会在较大的代码块中引入细微的错误,这可能会令人沮丧。

我还会将safely()调用移到f()函数之外,以便在每次运行时保存函数调用f()。如果您愿意,您可以使用 old-schooltry()代替,但您必须检查try-error哪一天可能会中断。你也可以tryCatch()把它包起来,但这种safely()方式对我来说似乎更干净。

于 2016-09-11T13:49:38.580 回答