Search code examples
rdplyrlazy-evaluationrlangstandard-evaluation

Using binary operator in lazyeval call with rlang


Let's say I want to add 1 to every value of a column using dplyr and standard evaluation.

I can do :

library(dplyr)
data <- head(iris)
var <- "Sepal.Length"
mutate(data, !!rlang::sym(var) := !!quo(`+`(!!rlang::sym(var), 1)))

But what if I would like to use + as binary operator and not as function ? I can't figure out how to write the + with a symbol in a quosure. In most of my attempts I got an error for trying to use a non-numeric argument (the symbol for example) with the binary operator +.

With the deprecated mutate_ you can use lazyeval::interp which allowed you to do it easily :

mutate_(data, .dots = setNames(list(lazyeval::interp(~var + 1, var = as.symbol(var))), var))

Any help would be appreciated. Thanks.


Solution

  • You can just use

    mutate(data, !!rlang::sym(var) := (!!rlang::sym(var)) + 1)
    

    Note the parenthesis around the bang-bang part. This is only necessary because you are probably using an older version of rlang. In older versions (<0.2) the !! has a very low precedence so the addition happens before the expansion. Starting with rlang 0.2 the !! has been given a different operator precedence and works more how you might expect.

    Of course if you are applyting the same transformation to a bunch of columns, you might want to use the mutate_at, mutate_all, or mutate_if versions, which also allow the transformations to be specific with the formula syntax.

    mutate_if(data, is.numeric, ~.x+1)
    mutate_all(data, ~.x+1)
    mutate_at(data, var, ~.x+1)