Search code examples
rdplyrrlang

Use variables from tidy select within paste()


Assume the following function

library(tidyverse)
nest_fun <- function(data, groups) {
  data %>% 
    group_by(pick({{groups}})) %>% 
    nest() %>% 
    mutate(filename = paste({{groups}}[1], {{groups}}[2], "file.png", sep = "_"))
}
nest_fun(data = mtcars, groups = c(vs, am))
# # A tibble: 4 × 4
# # Groups:   vs, am [4]
#      vs    am data              filename    
#   <dbl> <dbl> <list>            <chr>       
# 1     0     1 <tibble [6 × 9]>  0_1_file.png
# 2     1     1 <tibble [7 × 9]>  1_1_file.png
# 3     1     0 <tibble [7 × 9]>  1_0_file.png
# 4     0     0 <tibble [12 × 9]> 0_0_file.png

The function works fine as long as I group by exactly 2 variables. How could I write the function such that I can group by an arbitrary number of variables and still get filename correct?


Solution

  • The collapse argument of paste (and paste0) pastes down the elements of a vector, whereas sep pastes across the arguments of the call. Therefore you can get what you want with nested calls to paste/paste0.

    I strongly support @r2evans' comment about providing the data frame as an argument to your function. It is simply good practice (and allows you to pipe your function if you wish). I see you've already actioned that in the question. However, using data - which is the name of a built-in function - as its name is not ideal.

    So...

    library(tidyverse)
    
    nest_fun <- function(d=mtcars, groups = c(vs, am)) {
      d %>% 
        group_by(pick({{groups}})) %>% 
        nest() %>% 
        mutate(filename = paste0(paste({{groups}}, collapse="_"), "_file.png"))
    }
    
    nest_fun()
    
    # A tibble: 4 × 4
    # Groups:   vs, am [4]
         vs    am data              filename    
      <dbl> <dbl> <list>            <chr>       
    1     0     1 <tibble [6 × 9]>  0_1_file.png
    2     1     1 <tibble [7 × 9]>  1_1_file.png
    3     1     0 <tibble [7 × 9]>  1_0_file.png
    4     0     0 <tibble [12 × 9]> 0_0_file.png
    
    mtcars %>% nest_fun(c(vs, am, gear))
    
    # A tibble: 7 × 5
    # Groups:   vs, am, gear [7]
         vs    am  gear data              filename      
      <dbl> <dbl> <dbl> <list>            <chr>         
    1     0     1     4 <tibble [2 × 8]>  0_1_4_file.png
    2     1     1     4 <tibble [6 × 8]>  1_1_4_file.png
    3     1     0     3 <tibble [3 × 8]>  1_0_3_file.png
    4     0     0     3 <tibble [12 × 8]> 0_0_3_file.png
    5     1     0     4 <tibble [4 × 8]>  1_0_4_file.png
    6     0     1     5 <tibble [4 × 8]>  0_1_5_file.png
    7     1     1     5 <tibble [1 × 8]>  1_1_5_file.png
    nest_fun()