7

I need to filter a table by a logical column (or, more precisely, by its negation), but the name of the column may vary. It's easy when I know their names beforehand:

tb = tibble(
  id = 1:4, 
  col1 = c(TRUE, TRUE, FALSE, FALSE), 
  col2 = c(TRUE, FALSE, TRUE, FALSE)
)

tb
## # A tibble: 4 x 3
##      id  col1  col2
##   <int> <lgl> <lgl>
## 1     1  TRUE  TRUE
## 2     2  TRUE FALSE
## 3     3 FALSE  TRUE
## 4     4 FALSE FALSE

colname = quo(col1)

tb %>% 
  filter(!!colname) # rows where col1 is true
## # A tibble: 2 x 3
##      id  col1  col2
##   <int> <lgl> <lgl>
## 1     1  TRUE  TRUE
## 2     2  TRUE FALSE

tb %>% 
  filter(!(!!colname)) # rows where col1 is false
## # A tibble: 2 x 3
##      id  col1  col2
##   <int> <lgl> <lgl>
## 1     3 FALSE  TRUE
## 2     4 FALSE FALSE

colname = quo(col2)

tb %>% 
  filter(!!colname) # rows where col2 is true
## # A tibble: 2 x 3
##      id  col1  col2
##   <int> <lgl> <lgl>
## 1     1  TRUE  TRUE
## 2     3 FALSE  TRUE

tb %>% 
  filter(!(!!colname)) # rows where col2 is false
## # A tibble: 2 x 3
##      id  col1  col2
##   <int> <lgl> <lgl>
## 1     2  TRUE FALSE
## 2     4 FALSE FALSE

I could not, though, figure out how to do the same when the column names are stored in strings. For instance:

colname = "col1"
tb %>% 
  filter(!!colname) 
## Error in filter_impl(.data, quo): Argument 2 filter condition does not evaluate to a logical vector

colname = quo("col1")
tb %>% 
  filter(!!colname)
## Error in filter_impl(.data, quo): Argument 2 filter condition does not evaluate to a logical vector

colname = quo(parse(text = "col1"))
tb %>% 
  filter(!!colname) 
## Error in filter_impl(.data, quo): Argument 2 filter condition does not evaluate to a logical vector

So, the question is, how should I do it?

Edit: This is not a duplicate of this question because the preferred way to do non-standard evaluation with dplyr has changed since then. All functions terminated in _ are now deprecated, and the tidy evaluation framework is recommended now.

Luiz Rodrigo
  • 936
  • 1
  • 7
  • 19
  • Possible duplicate of [Filter data frame by character column name (in dplyr)](https://stackoverflow.com/questions/27197617/filter-data-frame-by-character-column-name-in-dplyr) – jdb Jul 21 '17 at 16:50
  • 1
    @jdb All solutions provided there use deprecated functions, the internal semantics has changed since then. – Luiz Rodrigo Jul 21 '17 at 16:51
  • Possible duplicate of [Programming with dplyr using string as input](https://stackoverflow.com/questions/44121728/programming-with-dplyr-using-string-as-input) – aosmith Jul 21 '17 at 17:34

1 Answers1

7

We can use sym from rlang for evaluating strings

library(rlang)
library(dplyr)
colname <- "col1"

tb %>% 
    filter(!!sym(colname))
# A tibble: 2 x 3
#     id  col1  col2
#  <int> <lgl> <lgl>
#1     1  TRUE  TRUE
#2     2  TRUE FALSE
akrun
  • 874,273
  • 37
  • 540
  • 662
  • 1
    Precisely what I needed, thank you! I guess this is a very common use case, don't know why `sym` is not mentioned in the "Programming with dplyr" vignette. – Luiz Rodrigo Jul 21 '17 at 16:54