Search code examples
rdplyrtidyversetidyeval

Writing a custom case_when function to use in dplyr mutate using tidyeval


I'm trying to write a custom case_when function to use inside dplyr. I've been reading through the tidyeval examples posted in other questions, but still can't figure out how to make it work. Here's a reprex:

df1 <- data.frame(animal_1 = c("Horse", "Pig", "Chicken", "Cow", "Sheep"),
           animal_2 = c(NA, NA, "Horse", "Sheep", "Chicken"))


translate_title <- function(data, input_col, output_col) {
  mutate(data, 
    !!output_col := case_when(
    input_col == "Horse" ~ "Cheval",
    input_col == "Pig" ~ "Рorc",
    input_col == "Chicken" ~ "Poulet",
    TRUE ~ NA)
  )
}


df1 %>% 
  translate_title("animal_1", "animaux_1") %>% 
  translate_title("animal_2", "animaux_2")

When I try to run this, I'm getting Error in mutate_impl(.data, dots) : Evaluation error: must be type string, not logical.

Also I would actually like to rewrite the function so that it can be used like this:

df1 %>% 
  mutate(animaux_1 = translate_title(animal_1),
         animaux_2 = translate_title(animal_2)
         )

But not sure how.


Solution

  • Depending on how you want to pass your input to the function you can solve it in two ways :

    1) Pass input as unquoted using {{}}

    library(dplyr)
    
    translate_title <- function(data, input_col, output_col) {
    
       mutate(data, 
            !!output_col := case_when(
            {{input_col}} == "Horse" ~ "Cheval",
            {{input_col}} == "Pig" ~ "Рorc",
            {{input_col}} == "Chicken" ~ "Poulet",
            TRUE ~ NA_character_)
      )
    }
    
    df1 %>% 
      translate_title(animal_1, "animaux_1") %>%
      translate_title(animal_2, "animaux_2")
    
    #  animal_1 animal_2 animaux_1 animaux_2
    #1    Horse     <NA>    Cheval      <NA>
    #2      Pig     <NA>      Рorc      <NA>
    #3  Chicken    Horse    Poulet    Cheval
    #4      Cow    Sheep      <NA>      <NA>
    #5    Sheep  Chicken      <NA>    Poulet
    

    2) Pass input quoted using sym and !!

    translate_title <- function(data, input_col, output_col) {
       mutate(data, 
             !!output_col := case_when(
              !!sym(input_col) == "Horse" ~ "Cheval",
              !!sym(input_col) == "Pig" ~ "Рorc",
              !!sym(input_col) == "Chicken" ~ "Poulet",
              TRUE ~ NA_character_)
      )
    }
    
    df1 %>% 
      translate_title("animal_1", "animaux_1") %>%
      translate_title("animal_2", "animaux_2")