2

Suppose I have a simple function that uses eval(substitue) with an object of class data.table:

f <- function(df,col) eval(substitute(df[,mean(col)]))

If I then have a simple data.table (d), with columns b1 and b2, I can call this function f(), as follows:

d <- data.table(b1 = c(1,2,3), b2 = c(4,5,6))

f(d,b1)
[1] 2

f(d,b2)
[1] 5

However, occasionally, the target column is stored as follows

n <- 1
target <- paste0("b", n)

Obviously, I cannot do f(d,target). I realize that I can do f(d,eval(parse(text = target))). Is there a better option to pass target to the function f(), without changing the current structure/signature of f()?

langtang
  • 22,248
  • 1
  • 12
  • 27

1 Answers1

2

We can tryCatch and use one of two methods:

f <- function(df,col) {
  if (tryCatch(is.character(col), error = function(e) FALSE)) {
    col <- as.name(col)
  }
  eval(substitute(df[,mean(col)]))
}
f(d, b1)
# [1] 2
f(d, "b1")
# [1] 2
f(d, b2)
# [1] 5
f(d, "b2")
# [1] 5

Internally, is.character(col) either returns TRUE (as in target) or fails with Error: object 'b1' not found, which is when the tryCatch kicks in.

r2evans
  • 141,215
  • 6
  • 77
  • 149
  • thanks for input, v helpful. Problem is that `f()` is much more complicated than I've shown (but still wrapped in `eval(substitute())`). Your solution works, but requires the full logic of `f()` to be repeated in both conditions of the if else.. – langtang Apr 25 '23 at 14:41
  • 1
    Gotcha ... see my edit, better I think. @langtang – r2evans Apr 25 '23 at 14:46
  • 1
    this method gets sketchy if `length(col) > 1`; for instance `f(d, c(b1,b2))` works as intended (3.5) but `f(d, c("b1","b2"))` does not. – r2evans Apr 25 '23 at 14:47