1

I'm creating a function for my co-workers to easily analyze some pre-specified datasets. I would like for them to be able to pass "i" arguments to select rows. To make it more robust, I would like to be able pass this argument with or without quotes.

Here is an example that works with quotes …

x <- data.table(x = c(1,1,1,2,2,2,3,3,3), 
  sex = c("M", "M", "F","M", "F","M", "F","M", "F"))
test.function <- function(my.dt, ...){
  where <- parse(text = paste0(list(...))) 
  my.dt <- my.dt[eval(where), ]
  return(my.dt)
}
tmp <- test.function(x, 'x==3 | sex=="F"')
head(tmp) 

If I remove the quotes, it fails saying "object 'sex' not found"…

x <- data.table(x = c(1,1,1,2,2,2,3,3,3), 
  sex = c("M", "M", "F","M", "F","M", "F","M", "F"))
test.function <- function(my.dt, ...){
  where <- parse(text = paste0(list(...))) 
  my.dt <- my.dt[eval(where), ]
  return(my.dt)
}
tmp <- test.function(x, x==3 | sex=="F")
head(tmp)

In addition to the above, I have many failed attempts using quote, substitution and rlang: like this failed example …

x <- data.table(x = c(1,1,1,2,2,2,3,3,3), 
                sex = c("M", "M", "F","M", "F","M", "F","M", "F"))
test.function <- function(my.dt, ...){
  where <- rlang::quos(...)
  my.dt <- my.dt[!!where, ]
  return(my.dt)
}
tmp <- test.function(x, 'x==3 | sex=="F"')
head(tmp, 10)

In addition to any ideas for solutions, I would be grateful if someone could point me toward an simpleton's online resource for understanding symbols/expressions/quotes/etc. As I dug into this problem I realized that I have some serious gaps in my understanding of how R works.

BTW, I've already read through the following, but neither was able to help me: Passing function argument to data.table i and Passing multiple arguments to data.table inside a function .

qdan
  • 45
  • 6
  • How about passing x, sex, and the operator as separate arguments? test.function(x, 3, "F", "|"). Then set up your function to handle each input as a separate variable? – Chris Nov 08 '19 at 19:59
  • Thanks for your comment Chris. I'm trying to keep this as simple as possible for the end user, who will not be a proficient R user. That's why I want I want them to be able to pass the argument with or without quotes. Thanks again. – qdan Nov 08 '19 at 20:26
  • If you remove quotes you should not use parse anymore. Parse expects character, not an expression. – jangorecki Nov 09 '19 at 03:33
  • Thank you @jangorecki. After seeing Matt's solution, that became clear to me. – qdan Nov 12 '19 at 22:02

1 Answers1

1

There may be other (better) options, but you can wrap it in tryCatch and use bquote for the unquoted argument

test.function <- function(my.dt, ...){
    where <- tryCatch(parse(text = paste0(list(...))),  error = function (e) parse(text = paste0(list(bquote(...)))))
    my.dt <- my.dt[eval(where), ]
    return(my.dt)
  }

tmp <- test.function(x, 'x==3 | sex=="F"')
head(tmp) 
   x sex
1: 1   F
2: 2   F
3: 3   F
4: 3   M
5: 3   F

tmp <- test.function(x, x==3 | sex=='F')
head(tmp)
   x sex
1: 1   F
2: 2   F
3: 3   F
4: 3   M
5: 3   F
Matt
  • 2,947
  • 1
  • 9
  • 21