Apply the glue function to all characted columns of with fields filled from the tibble

160 views Asked by At

I need to allow the users of a function to add new columns with strings created from the values of the supplied tibble. A simple illustration:

df <- data.frame(session=rep(LETTERS[1:3],2),
                 bundle=rep(letters[1:2],3),
                 xn1=sample(1:100,6),
                 xn2=sample(1:100,6))

myfun <- function(df, ...){
  dplyr::mutate(.data=df,!!!rlang::enexprs(...)) |>
    dplyr::mutate(across(where(is.character),~ glue::glue))
}

myfun(df,a=session,b="dsds{session}") 

which if the df is this:

> df
  session bundle xn1 xn2
1       A      a  31  95
2       B      b  45  64
3       C      a  12  38
4       A      b  56  13
5       B      a  70  93
6       C      b  53  73

then I want to get this output if myfun


> myfun(df,a=session,b="dsds{a}")
  session bundle xn1 xn2 a b
1       A      a  31  95 A dsdsA
2       B      b  45  64 B dsdsB 
3       C      a  12  38 C dsdsC
4       A      b  56  13 D dsdsA
5       B      a  70  93 B dsdsB
6       C      b  53  73 C dsdsC
 

But right now I get the errors that glue could not find the session values.

Error in `dplyr::mutate()` at test.R:14:2:
ℹ In argument: `across(where(is.character), ~glue::glue)`.
Caused by error in `across()`:
! Can't compute column `a`.
Caused by error in `dplyr_internal_error()`:
Run `rlang::last_trace()` to see where the error occurred.

Please note that I am not just trying to change the tibble. What I need is to create the myfun() function that would allow the user to create columns in the tibble flexibly.

2

There are 2 answers

1
lotus On BEST ANSWER

Is this what you're after? This changes character arguments into glue expressions before splicing everything into mutate():

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

myfun <- function(.data, ...){
  vars <- exprs(...)
  vars <- lapply(vars, \(x)  if (is.character(x)) expr(glue(!!x)) else x)
  mutate(.data = .data, !!!vars) 
}

myfun(df, a = session, b = "dsds{a}", a_and_b = "{a} and {b}") 

  session bundle xn1 xn2 a     b     a_and_b
1       A      a  25  61 A dsdsA A and dsdsA
2       B      b 100  66 B dsdsB B and dsdsB
3       C      a  86  26 C dsdsC C and dsdsC
4       A      b  27  33 A dsdsA A and dsdsA
5       B      a  58  20 B dsdsB B and dsdsB
6       C      b   7  74 C dsdsC C and dsdsC
3
Jon Spring On

How about this?

myfun2 <- function(df, colname, glue_phrase) {
  dplyr::mutate(df, {{ colname }} := glue::glue({{ glue_phrase }}))
}
    
df %>%
  myfun2(a, "{session}") %>%
  myfun2(b, "dsds{session}")

  session bundle xn1 xn2 a     b
1       A      a  38  70 A dsdsA
2       B      b  20  40 B dsdsB
3       C      a  28  44 C dsdsC
4       A      b  99  25 A dsdsA
5       B      a  44 100 B dsdsB
6       C      b  87  39 C dsdsC