Dplyr: Filter not working with quo_name

Created on 31 Oct 2017  路  3Comments  路  Source: tidyverse/dplyr

When trying to filter a column using quo_name, filter is not working as expected. Please see below reprex using dplyr 0.7.4

set.seed(1000)
df <- data.frame(x = sample(100,100,T), y = sample(letters,100,T), z = sample(c("One","Two","Three"),100,T))

func <- function(letter){
  letter <- enquo(letter)
  df %>%
    group_by(z) %>%
    summarise(!!quo_name(letter) := sum(x)) %>%
    filter(!!quo_name(letter) < 1600)
}

func(a)

# A tibble: 3 x 2
       z     a
  <fctr> <int>
1    One  1412
2  Three  1614
3    Two  1808

Expected output:

# A tibble: 2 x 2
       z     a
  <fctr> <int>
1    One  1412

If I filter outside of the function, the output is the expected: func(a) %>% filter(a < 1600)

Most helpful comment

This works

library(dplyr, warn.conflicts = F)
set.seed(1000)
df <- data.frame(x = sample(100,100,T), y = sample(letters,100,T), z = sample(c("One","Two","Three"),100,T))

func <- function(letter){
  letter <- enquo(letter)
  df %>%
    group_by(z) %>%
    summarise(!! quo_name(letter) := sum(x)) %>%
    filter((!! letter) < 1600)
}

func(a)
#> # A tibble: 1 x 2
#>        z     a
#>   <fctr> <int>
#> 1    One  1412

Per Programming with dplyr vignettes, in filter do not use quo_name. quo_name is useful with := operator because LHS expect a string or a symbol.
It is why I think this is not the issue.

Don't know why but it seems you need parenthesis in filter((!! letter) < 1600). filter(!!letter < 1600) does not seems to work. Again, it is used in the vignette so it seems correct.

Hopes it helps !

All 3 comments

This works

library(dplyr, warn.conflicts = F)
set.seed(1000)
df <- data.frame(x = sample(100,100,T), y = sample(letters,100,T), z = sample(c("One","Two","Three"),100,T))

func <- function(letter){
  letter <- enquo(letter)
  df %>%
    group_by(z) %>%
    summarise(!! quo_name(letter) := sum(x)) %>%
    filter((!! letter) < 1600)
}

func(a)
#> # A tibble: 1 x 2
#>        z     a
#>   <fctr> <int>
#> 1    One  1412

Per Programming with dplyr vignettes, in filter do not use quo_name. quo_name is useful with := operator because LHS expect a string or a symbol.
It is why I think this is not the issue.

Don't know why but it seems you need parenthesis in filter((!! letter) < 1600). filter(!!letter < 1600) does not seems to work. Again, it is used in the vignette so it seems correct.

Hopes it helps !

@cderv You have it: it is all about operator precedence. !!a := b parses as "assign b to !!a", !!a < b parses as "Apply !! to (a(!!a) < b parses to "(apply !! to a) < b" (the intended effect). Roughly "!!" binds late (doesn't aggressively grab the nearest term), and := and < don't have the same expression operator parsing precedence (so expressions with them to not parse the same).

H cderv,

Thank you for the clarification! That indeed works as expected. I followed the vignette, but obviously I misread that part.

Kind regards,

Was this page helpful?
0 / 5 - 0 ratings