1

Using the dplyr package in R, I want to pass a filter statement as a parameter in a function. I don't know how to evaluate the statement as code instead of a string. When I try the code below, I get an error message. I'm assuming I need a quosure or something, but I don't fully grasp that concept.

data("PlantGrowth")

myfunc <- function(df, filter_statement) {
  df %>%
    filter(!!filter_statement)
}

myfunc(PlantGrowth, "group %in% c('trt1', 'trt2')")

>  Error: Argument 2 filter condition does not evaluate to a logical vector 

# Want to do the same as this:
# PlantGrowth %>%
#   filter(group %in% c('trt1', 'trt2'))
oatmilkyway
  • 429
  • 1
  • 6
  • 17

1 Answers1

5

You can use parse_expr from rlang

library(dplyr)

myfunc <- function(df, filter_statement) {
   df %>% filter(eval(rlang::parse_expr(filter_statement)))
}

identical(myfunc(PlantGrowth, "group %in% c('trt1', 'trt2')"), 
      PlantGrowth %>% filter(group %in% c('trt1', 'trt2')))

#[1] TRUE

The same can be done using infamous eval and parse.

myfunc <- function(df, filter_statement) {
   df %>% filter(eval(parse(text = filter_statement)))
}
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
  • Sweet! Thank you! I never understand when to use `!!` or `quo()` or `eval()`... – oatmilkyway May 09 '20 at 05:54
  • 1
    Same. For me it's always trial and error ;-) – Ronak Shah May 09 '20 at 05:56
  • 1
    Interesting that `eval/parse` is frowned upon. However, `parse_exprs` includes a call to `parse(text=)` which in my opinion looks like the same thing named differently. Perhaps I should learn how `!!` works but often it seems like masking what is being done in `base` – NelsonGon May 09 '20 at 06:45
  • 1
    Yes, personally I would prefer to pass `group` and `c('trt1', 'trt2')` as two separate parameters instead of passing condition in the string `"group %in% c('trt1', 'trt2')"` and evaluating it. – Ronak Shah May 09 '20 at 07:14