Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mutate using glue in a user defined function

Tags:

r

dplyr

r-glue

I would like to change the values in a specific column to include information from another column using the glue function.

I do it normally like this:

library(glue)
library(dplyr)
df = data.frame(x = c("Banana","Apple","Melon"),
                y = c(10,15,27),
                z = rep(c("something_else"),3))
df %>%
  mutate(x = glue("{x} ({y})"))

The output:

#>             x  y              z
#> 1 Banana (10) 10 something_else
#> 2  Apple (15) 15 something_else
#> 3  Melon (27) 27 something_else

My proplem arises when I try to do the same thing using the dataframe and the column names as inputs in a user defined function.

My intitial instict is to pass the inputs using double curly braces in conjunction with the glue function, but this results in an error.

concatenate_value_to_string <- function(tbl,var1,var2) {
  tbl %>%
    mutate({{var1}} := glue("{{{var1}}} ({{{var2}}})"))
}

concatenate_value_to_string(df,x,y)
#> Error in UseMethod("mutate"): no applicable method for 'mutate' applied to an object of class "function"

Created on 2021-08-02 by the reprex package (v2.0.0)

Clearly triple curly braces are not the solution here, could anyone help me out?

Thank you.

like image 858
Ran K Avatar asked Sep 11 '25 17:09

Ran K


2 Answers

You could use dplyr::pull():

concatenate_value_to_string <- function(tbl,var1,var2) {
  tbl %>%
    mutate({{var1}} :=  glue("{pull(., {{var1}})} ({pull(., {{var2}})})"))
}

concatenate_value_to_string(df,x,y)

concatenate_value_to_string(df,x,y)
#>             x  y              z
#> 1 Banana (10) 10 something_else
#> 2  Apple (15) 15 something_else
#> 3  Melon (27) 27 something_else

Or eval(rlang::expr()), where we first build the symbol from the input then evaluate it in the context of the data frame.

concatenate_value_to_string <- function(tbl,var1,var2) {
  tbl %>%
    mutate({{var1}} :=  glue("{eval(expr({{var1}}))} ({eval(expr({{var2}}))})"))
}

concatenate_value_to_string(df,x,y)
#>             x  y              z
#> 1 Banana (10) 10 something_else
#> 2  Apple (15) 15 something_else
#> 3  Melon (27) 27 something_else

What you tried doesn't work because mutate() doesn't substitute {{foo}} if it's part of a string, in the solutions above, pull() or expr() do it.

Personally I'd rather use sprintf() in this case:

concatenate_value_to_string <- function(tbl,var1,var2) {
  tbl %>%
    mutate({{var1}} :=  sprintf("%s (%s)", {{var1}}, {{var2}}))
}

concatenate_value_to_string(df,x,y)
#>             x  y              z
#> 1 Banana (10) 10 something_else
#> 2  Apple (15) 15 something_else
#> 3  Melon (27) 27 something_else
like image 100
Moody_Mudskipper Avatar answered Sep 14 '25 06:09

Moody_Mudskipper


Another option could be:

concatenate_value_to_string <- function(tbl, var1, var2) {
    tbl %>%
        mutate(!!var1 := glue("{.data[[var1]]} ({.data[[var2]]})")) 
}

concatenate_value_to_string(df, "x", "y")

            x  y              z
1 Banana (10) 10 something_else
2  Apple (15) 15 something_else
3  Melon (27) 27 something_else
like image 40
tmfmnk Avatar answered Sep 14 '25 08:09

tmfmnk