How to use glue strings with dplyr::arrange in a function

I can't work out how to pass a string to a function and then have that function use glue (or paste) to create a variable name which is then passed to dplyr::arrange()

Here are 16 failed attempts:

library(dplyr, warn.conflicts = FALSE)

arr1 <- function(df, var) {
  df %>% 
    dplyr::arrange("{var}_color")
}
arr2 <- function(df, var) {
  df %>% 
    dplyr::arrange(!!"{var}_color")
}
arr3 <- function(df, var) {
  df %>% 
    dplyr::arrange(paste0(var, "_color"))
}
arr4 <- function(df, var) {
  df %>% 
    dplyr::arrange({{ "{var}_color" }})
}
arr5 <- function(df, var) {
  df %>% 
    dplyr::arrange(!!paste0(var, "_color"))
}
arr6 <- function(df, var) {
  var <- rlang::as_label(paste0(var, "_color"))
  df %>% 
    dplyr::arrange(var)
}
arr7 <- function(df, var) {
  var <- rlang::ensym(paste0(var, "_color"))
  df %>% 
    dplyr::arrange(!!var)
}
arr8 <- function(df, var) {
  var <- rlang::ensym(paste0(var, "_color"))
  df %>% 
    dplyr::arrange({{ var }})
}
arr9 <- function(df, var) {
  var <- rlang::ensym("{var}_color")
  df %>% 
    dplyr::arrange(!!var)
}
arr10 <- function(df, var) {
  df %>% 
    dplyr::arrange("{var}_color")
}
arr11 <- function(df, var) {
  df %>% 
    dplyr::arrange("{{ {var}_color }}")
}
arr12 <- function(df, var) {
  var <- rlang::enquo(paste0(var, "_color"))
  df %>% 
    dplyr::arrange(!!var)
}
arr13 <- function(df, var) {
  var <- rlang::enquo(paste0(var, "_color"))
  df %>% 
    dplyr::arrange({{ var }})
}
arr14 <- function(df, var) {
  var <- rlang::enquo("{var}_color")
  df %>% 
    dplyr::arrange(!!var)
}
arr15 <- function(df, var) {
  var <- as.name(paste0(var, "_color"))
  df %>% 
    dplyr::arrange(!!var)
}
arr16 <- function(df, var) {
  var <- as.name(paste0(var, "_color"))
  df %>% 
    dplyr::arrange({{ var }})
}


sw_select <- starwars %>% 
  head(3) %>% 
  dplyr::select(name:eye_color)

sw_select %>% 
  arr1("eye")
#> # A tibble: 3 x 6
#>   name           height  mass hair_color skin_color  eye_color
#>   <chr>           <int> <dbl> <chr>      <chr>       <chr>    
#> 1 Luke Skywalker    172    77 blond      fair        blue     
#> 2 C-3PO             167    75 <NA>       gold        yellow   
#> 3 R2-D2              96    32 <NA>       white, blue red
sw_select %>% 
  arr2("eye")
#> # A tibble: 3 x 6
#>   name           height  mass hair_color skin_color  eye_color
#>   <chr>           <int> <dbl> <chr>      <chr>       <chr>    
#> 1 Luke Skywalker    172    77 blond      fair        blue     
#> 2 C-3PO             167    75 <NA>       gold        yellow   
#> 3 R2-D2              96    32 <NA>       white, blue red
sw_select %>% 
  arr3("eye")
#> # A tibble: 3 x 6
#>   name           height  mass hair_color skin_color  eye_color
#>   <chr>           <int> <dbl> <chr>      <chr>       <chr>    
#> 1 Luke Skywalker    172    77 blond      fair        blue     
#> 2 C-3PO             167    75 <NA>       gold        yellow   
#> 3 R2-D2              96    32 <NA>       white, blue red
sw_select %>% 
  arr4("eye")
#> Error: `arg` must be a symbol
sw_select %>% 
  arr5("eye")
#> # A tibble: 3 x 6
#>   name           height  mass hair_color skin_color  eye_color
#>   <chr>           <int> <dbl> <chr>      <chr>       <chr>    
#> 1 Luke Skywalker    172    77 blond      fair        blue     
#> 2 C-3PO             167    75 <NA>       gold        yellow   
#> 3 R2-D2              96    32 <NA>       white, blue red
sw_select %>% 
  arr6("eye")
#> # A tibble: 3 x 6
#>   name           height  mass hair_color skin_color  eye_color
#>   <chr>           <int> <dbl> <chr>      <chr>       <chr>    
#> 1 Luke Skywalker    172    77 blond      fair        blue     
#> 2 C-3PO             167    75 <NA>       gold        yellow   
#> 3 R2-D2              96    32 <NA>       white, blue red
sw_select %>% 
  arr7("eye")
#> Error: `arg` must be a symbol
sw_select %>% 
  arr8("eye")
#> Error: `arg` must be a symbol
sw_select %>% 
  arr9("eye")
#> Error: `arg` must be a symbol
sw_select %>% 
  arr10("eye")
#> # A tibble: 3 x 6
#>   name           height  mass hair_color skin_color  eye_color
#>   <chr>           <int> <dbl> <chr>      <chr>       <chr>    
#> 1 Luke Skywalker    172    77 blond      fair        blue     
#> 2 C-3PO             167    75 <NA>       gold        yellow   
#> 3 R2-D2              96    32 <NA>       white, blue red
sw_select %>% 
  arr11("eye")
#> # A tibble: 3 x 6
#>   name           height  mass hair_color skin_color  eye_color
#>   <chr>           <int> <dbl> <chr>      <chr>       <chr>    
#> 1 Luke Skywalker    172    77 blond      fair        blue     
#> 2 C-3PO             167    75 <NA>       gold        yellow   
#> 3 R2-D2              96    32 <NA>       white, blue red
sw_select %>% 
  arr12("eye")
#> Error: `arg` must be a symbol
sw_select %>% 
  arr13("eye")
#> Error: `arg` must be a symbol
sw_select %>% 
  arr14("eye")
#> Error: `arg` must be a symbol
sw_select %>% 
  arr15("eye")
#> # A tibble: 3 x 6
#>   name           height  mass hair_color skin_color  eye_color
#>   <chr>           <int> <dbl> <chr>      <chr>       <chr>    
#> 1 Luke Skywalker    172    77 blond      fair        blue     
#> 2 R2-D2              96    32 <NA>       white, blue red      
#> 3 C-3PO             167    75 <NA>       gold        yellow
sw_select %>% 
  arr16("eye")
#> # A tibble: 3 x 6
#>   name           height  mass hair_color skin_color  eye_color
#>   <chr>           <int> <dbl> <chr>      <chr>       <chr>    
#> 1 Luke Skywalker    172    77 blond      fair        blue     
#> 2 R2-D2              96    32 <NA>       white, blue red      
#> 3 C-3PO             167    75 <NA>       gold        yellow

Created on 2021-10-12 by the reprex package (v2.0.1)

It'll do the job, but pretty sure there's some better solution.

library(dplyr)
library(glue) 
library(rlang)

sw_select <- starwars %>%
  head(3) %>%
  select(name:eye_color)

glued_arrange <- function(df, var) {
  df %>%
    arrange(!!parse_expr(glue("{var}_color")))
}

sw_select %>% 
  glued_arrange("eye")
1 Like

Oh wow, no that's perfect.
I was flailing around as you can see from my examples, convinced it should be an ensym solution. Not sure if I ever would have realised it was parse_expr() I needed.

I was a bit distracted by other lines in my real life situation, where elsewhere in the function I can just use {var} in a glue expression on the LHS of a mutate call, but then later on I need to pass the expression to another function as a column name. Which is where I got stuck.

This is how I would do it, you need to first construct a symbol, then unquote it for the call.

arr17 <- function(df, var) {
  var <- rlang::sym(glue::glue("{var}_color"))
  df %>% 
    dplyr::arrange({{var}})
}

library(dplyr, warn.conflicts = FALSE)
sw_select <- starwars %>% 
  head(3) %>% 
  dplyr::select(name:eye_color)

arr17(sw_select, "eye")
#> # A tibble: 3 × 6
#>   name           height  mass hair_color skin_color  eye_color
#>   <chr>           <int> <dbl> <chr>      <chr>       <chr>    
#> 1 Luke Skywalker    172    77 blond      fair        blue     
#> 2 R2-D2              96    32 <NA>       white, blue red      
#> 3 C-3PO             167    75 <NA>       gold        yellow

Created on 2021-10-12 by the reprex package (v2.0.1)

In this case you could also use !! rather than {{ }}, but I guess I prefer the latter.

Thanks Jim, that's helpful.
I was pretty close with my attempts 7 and 8.
I thought I needed ensym() as it was within a function, working with function input.
My attempt 9 was also close but I stupidly forgot I would need to actually call glue in the top line, as I had moved the expression out of the arrange() line.

LOL I just noticed that my attempts 15 and 16 actually worked! :roll_eyes: :man_facepalming:t2:
Using head(3) instead of just head(6) – to save space – made it harder to see if it had worked.

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.