thothal
thothal

Reputation: 20329

Use string representation of variable in i for data.table

Apparently I am too stupid to enter the correct search terms, b/c I think that my question is not unique at all.

How to refer to a variable by string in the i part of data.table? with and ..x are all good for the j part, but what would be the equivalent in the i part? Do I have to use evil eval (pun intended ;)

library(data.table)
dt <- data.table(x = 1:4, y = 4:1)

my_filter_fun <- function(var = names(dt)) {
  var <- match.arg(var)
  dt[eval(parse(text = paste(var, "== 1")))]
}
my_filter_fun("x")
my_filter_fun("y")

What is the idiomatic way in data.table to do so? Coming from dplyr I think I am looking for the equivalent of quosures for data.table?

Bonus question: how could i implement my_filter_fun such that such a call

my_filter_fun(x > 1)

would return the same result as

dt[x > 1]

Upvotes: 2

Views: 1177

Answers (2)

s_baldur
s_baldur

Reputation: 33498

For your first question, I suggest using get() to avoid the evil of eval():

my_filter_fun <- function(var = names(dt)) {
  var <- match.arg(var)
  dt[get(var) == 1]
}
my_filter_fun("x")
   x y
1: 1 4

For the bonus question, you could do the following. It can be simplified though - just that I don't know how.

bonus_filter_fun <- function(filter) {
  filter <- deparse(substitute(filter))
  dt[eval(parse(text = filter))]
}
bonus_filter_fun(x > 1)
   x y
1: 2 3
2: 3 2
3: 4 1

Upvotes: 3

David T
David T

Reputation: 2143

You have to use esoteric R magic, but not eval. What you are asking about is NSE or non-standard evaluation. Here's an example similar to yours:

theDf <- tibble(Sticks = 4:7, Stones = 9:12)
#' @title Create a new column by adding 8 to one of the existing columns.
a8Col <- function(df, newName, existName){
  existName <- enquo(existName)
  df %>%
    mutate(!! newName := !! existName + 8L )
}

R > a8Col(theDf, "Bones", Sticks)
# A tibble: 4 x 3
Sticks Stones Bones
<int>  <int> <int>
1      4      9    12
2      5     10    13
3      6     11    14
4      7     12    15
R > a8Col(theDf, "Bones", Stones)
# A tibble: 4 x 3
Sticks Stones Bones
<int>  <int> <int>
1      4      9    17
2      5     10    18
3      6     11    19
4      7     12    20

Notice that I didn't have to put quotes around Sticks or Stones in the calls to a8Col.

NSE is a hard topic. Hadley Wickham has written two chapter on it, (Quasiquotation and Evaluation) in his "Advanced R" book.

Upvotes: 0

Related Questions