2

I am trying to unquote a string for use in dplyr::arrange. It does not appear to work. However, it appears to work correctly in dplyr::select. Am I missing something or doing something wrong here?


library(tidyverse)

df <- tibble(x = c(1, 2, 3),
             y = c(8, 6, 3))

v <- 'y'

# `select` works with `!!v` 

df %>% select(y)
#> # A tibble: 3 x 1
#>       y
#>   <dbl>
#> 1     8
#> 2     6
#> 3     3

df %>% select(!!v)
#> # A tibble: 3 x 1
#>       y
#>   <dbl>
#> 1     8
#> 2     6
#> 3     3

# `arrange` not work with `!!v`

df %>% arrange(y)
#> # A tibble: 3 x 2
#>       x     y
#>   <dbl> <dbl>
#> 1     3     3
#> 2     2     6
#> 3     1     8

df %>% arrange(!!v)
#> # A tibble: 3 x 2
#>       x     y
#>   <dbl> <dbl>
#> 1     1     8
#> 2     2     6
#> 3     3     3
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
mjandrews
  • 2,392
  • 4
  • 22
  • 39

2 Answers2

2

You need to convert your string to variable first (using sym()) then unquote it inside arrange().

df %>% arrange(!!sym(v))

#> # A tibble: 3 x 2
#>       x     y
#>   <dbl> <dbl>
#> 1     3     3
#> 2     2     6
#> 3     1     8

select() can directly take string input but it's not recommended

df %>% select(v)

#> Note: Using an external vector in selections is ambiguous.
#> i Use `all_of(v)` instead of `v` to silence this message.
#> i See <https://tidyselect.r-lib.org/reference/faq-external-vector.html>.
#> This message is displayed once per session.
#> # A tibble: 3 x 1
#>       y
#>   <dbl>
#> 1     8
#> 2     6
#> 3     3

Created on 2020-11-21 by the reprex package (v0.3.0)

Tung
  • 26,371
  • 7
  • 91
  • 115
  • 2
    It is generally better to use `.data` than `sym()`. The latter will work well most of the time but might have issues in rare corner cases. In general, if you don't have a good grasp of NSE, it's better to stick with `{{` and `.data`. – Lionel Henry Nov 23 '20 at 09:56
  • 1
    Regarding passing a string to `select()`, just wrap it in `all_of()`, as recommended in that warning message. – Lionel Henry Nov 23 '20 at 09:57
  • Thanks @LionelHenry! – Tung Nov 23 '20 at 16:09
2

In selecting verbs, use all_of() or any_of(). the former causes an error if not all variables are present in the data frame, the latter is lenient (and in general more useful for deselecting)

df %>% select(all_of(v))
#> # A tibble: 3 x 1
#>       y
#>   <dbl>
#> 1     8
#> 2     6
#> 3     3

In action verbs, like arrange() or mutate(), select single variables by subsetting the .data pronoun:

df %>% arrange(.data[[v]])
#> # A tibble: 3 x 2
#>       x     y
#>   <dbl> <dbl>
#> 1     3     3
#> 2     2     6
#> 3     1     8

You can also use selections in action verbs by using across():

df %>% arrange(across(starts_with("y")))
#> # A tibble: 3 x 2
#>       x     y
#>   <dbl> <dbl>
#> 1     3     3
#> 2     2     6
#> 3     1     8

Which means you can use all_of() as well to select from a character vector:

df %>% arrange(across(all_of(v)))
#> # A tibble: 3 x 2
#>       x     y
#>   <dbl> <dbl>
#> 1     3     3
#> 2     2     6
#> 3     1     8
Lionel Henry
  • 6,652
  • 27
  • 33