5

As a minimal working example, for instance, I want to be able to dynamically pass expressions to a data.table object to create new columns or modify existing ones:

dt <- data.table(x = 1, y = 2)
dynamicDT <- function(...) {
    dt[, list(...)]
}
dynamicDT(z = x + y)

I was expecting:

   z
1: 3

but instead, I get the error:

Error in eval(expr, envir, enclos) : object 'x' not found 

So how can I fix this?

Attempts:

I've seen this post, which suggests using quote or substitute, but

> dynamicDT(z = quote(x + y))
Error in `rownames<-`(`*tmp*`, value = paste(format(rn, right = TRUE),  : 
  length of 'dimnames' [1] not equal to array extent

or

> dynamicDT <- function(...) {
+     dt[, list(substitute(...))]
+ }
> dynamicDT(z = x + y)
Error in prettyNum(.Internal(format(x, trim, digits, nsmall, width, 3L,  : 
  first argument must be atomic

haven't worked for me.

5
  • You won't get that desired output if you will use list. If you function will work, the output will be z 1: 3. You need to use := Commented May 28, 2014 at 11:27
  • @DavidArenburg. Thanks for pointing that out - was an oversight when writing. Fixed now. Commented May 28, 2014 at 11:33
  • I actually wrote an answer for your original desired output, do you still need it Commented May 28, 2014 at 11:33
  • Sure - thanks David. Shouldn't be too hard to tweak the final output. The important bit is how you manage to pass expressions to be evaluated in context of the data.table rather than .GlobalEnv. Commented May 28, 2014 at 11:34
  • See my edit re multiple variables Commented May 28, 2014 at 12:03

2 Answers 2

9

This should be a better alternative to David's answer:

dynamicDT <- function(...) {
 dt[, eval(substitute(...))]
}

dynamicDT(z := x + y)
#   x y z
#1: 1 2 3
Sign up to request clarification or add additional context in comments.

3 Comments

(+1) Nice one @Roland, certainly better
Thanks - can this handle multiple arguments such as dynamicDT(a := x + y, b := x - y)?
It still has to be correct data.table syntax. See David's answer for the syntax.
3

You will need to use eval(parse(text = )) combination. parse will transform the string into an expression, while eval will evaluate it.

library(data.table)
dt <- data.table(x = 1, y = 2)
dynamicDT <- function(temp = "") {
  dt[, eval(parse(text = temp))]
}

In order to get your previous desired output

dynamicDT("z := x + y")
##    x y z
## 1: 1 2 3

In order to get your current desired output

dynamicDT("z = x + y")
## [1] 3

In order to parse multiple arguments you can do

dynamicDT('c("a","b") := list(x + y, x - y)')

##   x y a  b
##1: 1 2 3 -1

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.