0

I've got a function that uses tidyeval to refer to a column name, but also needs to access that column name as a string. The code for that works fine, see below (though improvements welcome, as_name(enquo(x)) seems clunky).

But I can't figure out how to write a wrapper function to use purrr::map() to maps over multiple columns using this function. Whatever I try either fails entirely or doesn't get the right string value of the column names.

library(dplyr, warn.conflicts = FALSE)
library(rlang, warn.conflicts = FALSE)
library(purrr, warn.conflicts = FALSE)
library(ggplot2, warn.conflicts = FALSE)  # for the mpg data

# This function takes a data frame and a column name using tidyeval. It uses the
# column name both in a dplyr tidyeval context, and it also gets the column name
# as a string.
inner_function <- function(df, x) {
  df %>% 
    distinct({{x}}) %>%  # Use column name in dplyr tidyeval context
    rename(level = {{x}}) %>% 
    mutate(term = rlang::as_name(rlang::enquo(x)))  # Column name as string
}



# The function works when used by itself
mpg %>% 
  inner_function(drv)
#> # A tibble: 3 × 2
#>   level term 
#>   <chr> <chr>
#> 1 f     drv  
#> 2 4     drv  
#> 3 r     drv

Created on 2023-06-29 with reprex v2.0.2

Oliver
  • 1,098
  • 1
  • 11
  • 16
  • You can use `rlang::englue("{{ x }}")` instead of `as_name(enquo(x))`. It's more idiomatic and makes it easy to add a prefix, suffix, or interpolate a normal string using single brace glue syntax e.g. `"fixed_prefix_{{ x }}_{var_suffix}"` – Lionel Henry Jun 30 '23 at 07:03

1 Answers1

0

You can have a wrapper function with dots as an input, and you need to turn them into a list of quosures using rlang::enquos(). Then when you're mapping over that list, use {{}} on the individual elements:

# Wrapper function to perform inner_function() for multiple variables
outer_function <- function(df, ...) {
  # Need to capture the dots as a list of quosures
  variables <- rlang::enquos(...)
  
  # And then use {{}} on the individual ones within the mapped function
  purrr::map_df(variables, \(x) inner_function(df, {{x}}))
}

# Works on a single column
mpg %>% 
  outer_function(drv)
#> # A tibble: 3 × 2
#>   level term 
#>   <chr> <chr>
#> 1 f     drv  
#> 2 4     drv  
#> 3 r     drv

# Works on multiple columns
mpg %>% 
  outer_function(drv, class)
#> # A tibble: 10 × 2
#>    level      term 
#>    <chr>      <chr>
#>  1 f          drv  
#>  2 4          drv  
#>  3 r          drv  
#>  4 compact    class
#>  5 midsize    class
#>  6 suv        class
#>  7 2seater    class
#>  8 minivan    class
#>  9 pickup     class
#> 10 subcompact class

Created on 2023-06-29 with reprex v2.0.2

Oliver
  • 1,098
  • 1
  • 11
  • 16