0

I have a function that uses tidyeval like select_this defined below. I have another function wrapper_select_this wrapping it, but I get the below error. Is there a simple way to adjust the wrapper_select_this to work (in this case: output the same as function select_this)?

library(tidyverse)

z <- c("a", "b")
df <- data.frame(Z = 1:3, a = 1:3, b = 1:3)

select_this <- function(df, x){
  x_upper <- enexpr(x) %>% str_to_upper
  
  df %>%
    select(
      all_of(x_upper), all_of(x)
    )
}

wrapper_select_this <- function(df, x){
  df %>% select_this(x)
  
}

df %>% select_this(z)
#>   Z a b
#> 1 1 1 1
#> 2 2 2 2
#> 3 3 3 3

df %>% wrapper_select_this(z)
#> Error: Can't subset columns that don't exist.
#> x Column `X` doesn't exist.

Created on 2022-04-07 by the reprex package (v2.0.1)

its.me.adam
  • 333
  • 2
  • 11

1 Answers1

1

If you change select_this() to support quosures, you can then use {{ to interface with it. In this case you can use as_name() to transform a potentially quosured symbol to a string:

z <- c("a", "b")
df <- data.frame(Z = 1:3, a = 1:3, b = 1:3)

select_this <- function(df, x) {
  x_upper <- toupper(rlang::as_name(enquo(x)))

  df %>%
    select(all_of(x_upper), all_of(x))
}

df %>% select_this(z)
#>   Z a b
#> 1 1 1 1
#> 2 2 2 2
#> 3 3 3 3

Then use {{ to interface with it:

wrapper_select_this <- function(df, x){
  df %>% select_this({{ x }})
}

df %>% wrapper_select_this(z)
#>   Z a b
#> 1 1 1 1
#> 2 2 2 2
#> 3 3 3 3

I have to say I find it a bit confusing that you're selecting columns both by defused name and by the column names contained in the env-var of the same name.

Lionel Henry
  • 6,652
  • 27
  • 33
  • Why not use `enexpr` in place of `enquo`? On your last note, I had objects SCALE_questions containg strings of scales of questions, and I wanted a function to select not only the questions, but also the SCALE_score sum of the questions based simply on the name of SCALE_questions. I agree it is confusing and I decided to simply add another variable to my function: SCALE. Now the function takes the SCALE name and the object containing the strings of questions (I did not want the object to contain the string of SCALE_score). – its.me.adam Apr 22 '22 at 17:11
  • 1
    In snippets like this I use `enquo()` when possible even when not needed because it's easy to use `enexpr()` in places where `enquo()` would be appropriate. Also `{{` uses `enquo()` under the hood so even with `enexpr()` you might get quosures, which is easy to forget. – Lionel Henry Apr 23 '22 at 18:59