Search code examples
rfunctionnon-standard-evaluation

Use a function's unnamed parameters ... in a glue::glue call


I want a function to glue two character variables together even when the name of one (or many) are not know until the function is called.

f <- function(t, str1, ...) {
  t %>% 
    mutate(name = glue::glue("{str1} {...}"))
}
s <- tidyr::tribble(
                    ~str1, ~str2,
                    "first", "second"
                    )
s
s %>% f(str1, str2)

The answer I want is the same as the result of this function and call where I assume the name of the second field is known.

f2 <- function(t, str1, ...) {
  t %>% 
    mutate(name = glue::glue("{str1} {str2}"))
}
s <- tidyr::tribble(
                    ~str1, ~str2,
                    "first", "second"
                    )
s
s %>% f2(str1, str2)

Solution

  • In general, ellipsis (...) can be used to pass an unknown number of named and unnamed arguments to a function. See here for an example.

    But there are different structures for passing bare variables like those frequently used in the Tidyverse. It gets slightly more complicated when there is an unknown number of them. For more, start here:

    The tidyeval link is a good foundation for this code, discussing quotation, and several of these functions.

    library(tidyverse)
    df <- tibble(
      a = LETTERS[1:10],
      b = letters[11:20]
    )
    
    mixed_bare_glue <- function(.df, .x, ...) {
      var_x <- enquo(.x)
      selected_vars <- enquos(...)
      full_sel_vars <- c(var_x, selected_vars)
    
      var_expr <- purrr::map(full_sel_vars, as_label) %>%
        purrr::map(~ paste0("{", .x, "}")) %>%
        purrr::reduce(paste)
      .df %>%
        mutate(name = glue::glue(var_expr))
    }
    
    mixed_bare_glue(df, a, b)
    #> # A tibble: 10 x 3
    #>    a     b     name  
    #>    <chr> <chr> <glue>
    #>  1 A     k     A k   
    #>  2 B     l     B l   
    #>  3 C     m     C m   
    #>  4 D     n     D n   
    #>  5 E     o     E o   
    #>  6 F     p     F p   
    #>  7 G     q     G q   
    #>  8 H     r     H r   
    #>  9 I     s     I s   
    #> 10 J     t     J t