Filter data frame by character column name (in dplyr)

Using rlang’s injection paradigm

From the current dplyr documentation (emphasis by me):

dplyr used to offer twin versions of each verb suffixed with an underscore. These versions had standard evaluation (SE) semantics: rather than taking arguments by code, like NSE verbs, they took arguments by value. Their purpose was to make it possible to program with dplyr. However, dplyr now uses tidy evaluation semantics. NSE verbs still capture their arguments, but you can now unquote parts of these arguments. This offers full programmability with NSE verbs. Thus, the underscored versions are now superfluous.

So, essentially we need to perform two steps to be able to refer to the value "this" of the variable column inside dplyr::filter():

  1. We need to turn the variable column which is of type character into type symbol.

    Using base R this can be achieved by the function as.symbol()
    which is an alias for as.name(). The former is preferred by the
    tidyverse developers
    because it

    follows a more modern terminology (R types instead of S modes).

    Alternatively, the same can be achieved by rlang::sym() from the tidyverse.

  2. We need to inject the symbol from 1) into the dplyr::filter() expression.

    This is done by the so called injection operator !! which is basically syntactic
    sugar
    allowing to modify a piece of code before R evaluates it.

    (In earlier versions of dplyr (or the underlying rlang respectively) there used to be situations (incl. yours) where !! would collide with the single !, but this is not an issue anymore since !! gained the right operator precedence.)

Applied to your example:

library(dplyr)
df <- data.frame(this = c(1, 2, 2),
                 that = c(1, 1, 2))
column <- "this"

df %>% filter(!!as.symbol(column) == 1)
#   this that
# 1    1    1

Using alternative solutions

Other ways to refer to the value "this" of the variable column inside dplyr::filter() that don’t rely on rlang’s injection paradigm include:

Leave a Comment