2

This is a curiosity question---I'll never actually need to do this, but I'm trying to understand R's quasiquotation and tidy evaluation features and I think this will help me with that.

Suppose you want to filter the droids from the starwars dataset:

library(dplyr)
library(rlang)

starwars %>% filter(species == "Droid")

Is it possible to do something like saving the filter call, and reuse it later? This would be useful for conciseness if there were many conditions to filter by. Something like

filter_droid = some_quote(filter(species == "Droid"))

starwars %>% some_unquote(filter_droid)

Of course, you could do it this way:

cond = expr(species == "Droid")

starwars %>% filter(eval(cond))

but this idea doesn't always work when there are multiple arguments. For instance when making two new columns with mutate, this doesn't work:

new_cols = exprs(col1 = 1, col2 = 2)

starwars %>% mutate(eval(new_cols))

If I were writing a script, I would fix this is by just defining a function that does the mutate call for me---for the sake of curiosity I want to ignore doing that. How can you "save" the mutate/filter call, or at least the arguments inside them, to use later in your code interactively?

Drew N
  • 123
  • 4
  • 2
    If there are multiple expressions in a list you can splice them with `!!!`, for instance `starwars %>% mutate(!!!new_cols)` – Lionel Henry Aug 21 '20 at 09:35

1 Answers1

4

You could make it a function

filt <- . %>% filter(species == "Droid")
starwars %>% filt

Or rather than using eval(), use the !! operator when injecting a single parameter

cond = expr(species == "Droid")
starwars %>% filter(!!cond)

or use !!! to inject multiple.

new_cols = exprs(col1 = 1, col2 = 2)
starwars %>% mutate(!!!new_cols)
MrFlick
  • 195,160
  • 17
  • 277
  • 295
  • What's the difference between using eval and !! in this case? It seems to do the same thing. – Drew N Aug 21 '20 at 08:53
  • 1
    @DrewN Precedence. `!!` forces immediate evaluation in the current context. The argument to `eval()`, on the other hand, may or may no be evaluated before all other parts of the expression. [This comes into play when writing complex expressions that involve multiple nested dplyr verbs](https://stackoverflow.com/a/51906044/300187). – Artem Sokolov Aug 21 '20 at 20:45
  • @DrewN in addition to the point made by Artem, you can't use `eval()` with `mutate()` to create multiple parameters. You would need to use `!!!` to expand into multiple parameters. – MrFlick Aug 21 '20 at 22:10