jonmaestro
jonmaestro

Reputation: 13

Arrange function in dplyr 0.7.1

I am trying to use the new quo functionality while writing a function utilizing dplyr and ran into the following issue:

df <- tibble(
  g1 = c(1, 1, 2, 2, 2),
  g2 = c(1, 2, 1, 3, 1),
  a = sample(5), 
  b = sample(5)
)

To arrange the dataframe by a variable is straightforward:

my_arrange <- function(df, arrange_var) {
  quo_arrange_var <- enquo(arrange_var)
  df %>%
    arrange(!!quo_arrange_var)
}

But what if I want to set a preferential order? For example, any arrange variable has 2 as the top variable and then sorts normally. With the previous version of dplyr I would use:

arrange(-(arrange_var == 2), arrange_var)

but in the new structure I am not sure how to approach. I have tried:

my_arrange <- function(df, arrange_var) {
  quo_arrange_var <- enquo(arrange_var)

  df %>%
    arrange(-!!quo_arrange_var==2, !!quo_arrange_var)
}

but I get the error

 Error in arrange_impl(.data, dots) : 
  incorrect size (1) at position 1, expecting : 5 

I have also tried using the quo_name:

my_arrange <- function(df, arrange_var) {
  quo_arrange_var <- enquo(arrange_var)

  df %>%
    arrange(-!!(paste0(quo_name(quo_arrange_var), "==2")), !!quo_arrange_var)
}

but get this error:

 Error in arrange_impl(.data, dots) : 
  Evaluation error: invalid argument to unary operator. 

any help would be appreciated

Upvotes: 1

Views: 1114

Answers (2)

dipetkov
dipetkov

Reputation: 3700

The tidyverse has evolved and there no need for enquo anymore. Instead we enclose expressions in double braces {{ }} (aka we embrace them).

library("tidyverse")

df <- tibble(
  g1 = c(1, 1, 2, 2, 2),
  g2 = c(1, 2, 1, 3, 1),
  a = sample(5),
  b = sample(5)
)

my_arrange <- function(df, arrange_var) {
  df %>%
    arrange(desc({{ arrange_var }} == 2), {{ arrange_var }})
}
my_arrange(df, g2)
#> # A tibble: 5 × 4
#>      g1    g2     a     b
#>   <dbl> <dbl> <int> <int>
#> 1     1     2     1     2
#> 2     1     1     4     5
#> 3     2     1     3     3
#> 4     2     1     5     1
#> 5     2     3     2     4

packageVersion("tidyverse")
#> [1] '1.3.1'

Created on 2022-03-17 by the reprex package (v2.0.1)

Upvotes: 0

MrFlick
MrFlick

Reputation: 206606

The easiest fix is to put parenthesis around the bang-bang. This has to do with operator precedence with respect to ! and ==. When you have !!a==b, it gets parsed as !!(a==b) even though you want (!!a)==b. And for some reason you can compare a quosure to a numeric value quo(a)==2 returns FALSE so you expression is evaluating to arrange(-FALSE, g2) which would give you the same error message.

my_arrange <- function(df, arrange_var) {
  quo_arrange_var <- enquo(arrange_var)

  df %>%
    arrange(-((!!quo_arrange_var)==2), !!quo_arrange_var)
}
my_arrange(df, g2)
# # A tibble: 5 x 4
#      g1    g2     a     b
#   <dbl> <dbl> <int> <int>
# 1     1     2     5     4
# 2     1     1     2     5
# 3     2     1     4     3
# 4     2     1     3     1
# 5     2     3     1     2

Upvotes: 1

Related Questions