Steen Harsted
Steen Harsted

Reputation: 1932

Is it possible to pass multible variables to the same curly curly?

I am building a function that uses {{ }} (curly curly or double mustache)

I would like the user to be able to pass multiple variables into the same {{ }}, but I am not sure if this is possible using {{ }}. I can't find any examples showing how to do this.

Can you tell me if it possible, and if yes help me make the below minimal reprex work?

library(tidyverse)

group_mean <- function(.data, group){
  .data %>% 
    group_by({{group}}) %>% 
    summarise_all(mean)

}

# Works
mtcars %>% 
  group_mean(group = cyl)

# Fails
mtcars %>% 
  group_mean(group = c(cyl, am)) 

Error: Column `c(cyl, am)` must be length 32 (the number of rows) or one, not 64 

Upvotes: 9

Views: 849

Answers (2)

Lionel Henry
Lionel Henry

Reputation: 6803

Edit 2022: Nowadays we'd tend to use the c() syntax of tidyselect for taking in multiple groups of variables.

library(dplyr)

my_mean <- function(data, group_vars, summary_vars) {
  data |>
    group_by(across({{ group_vars }})) |>
    summarise(across({{ summary_vars }}, \(x) mean(x, na.rm = TRUE)))
}

mtcars |> my_mean(c(cyl, am), c(mpg, disp))
#> `summarise()` has grouped output by 'cyl'. You can override using the
#> `.groups` argument.
#> # A tibble: 6 × 4
#> # Groups:   cyl [3]
#>     cyl    am   mpg  disp
#>   <dbl> <dbl> <dbl> <dbl>
#> 1     4     0  22.9 136.
#> 2     4     1  28.1  93.6
#> 3     6     0  19.1 205.
#> 4     6     1  20.6 155
#> 5     8     0  15.0 358.
#> 6     8     1  15.4 326

See also the Bidge patterns section in https://rlang.r-lib.org/reference/topic-data-mask-programming.html


If your function takes several groups of multiple variables, you need external quoting with vars(). This function simply capture its inputs as a list of expressions:

vars(foo, bar)
#> [[1]]
#> <quosure>
#> expr: ^foo
#> env:  global
#>
#> [[2]]
#> <quosure>
#> expr: ^bar
#> env:  global

Take an argument that you splice with !!!:

group_mean <- function(.data, .vars, ...) {
  .data <- doingsomethingelse(.data, ...)

  .data %>% 
     group_by(!!!.vars) %>% 
     summarise_all(mean)
}

Use it like this:

data %>% group_mean(vars(foo, bar), baz, quux)

Upvotes: 11

Ronak Shah
Ronak Shah

Reputation: 389135

For multiple grouping variables, you don't need curly-curly, pass three dots instead.

group_mean <- function(.data, ...){
  .data %>% 
     group_by(...) %>% 
     summarise_all(mean)
}


mtcars %>%  group_mean(cyl)

# A tibble: 3 x 11
#    cyl   mpg  disp    hp  drat    wt  qsec    vs    am  gear  carb
#  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#1     4  26.7  105.  82.6  4.07  2.29  19.1 0.909 0.727  4.09  1.55
#2     6  19.7  183. 122.   3.59  3.12  18.0 0.571 0.429  3.86  3.43
#3     8  15.1  353. 209.   3.23  4.00  16.8 0     0.143  3.29  3.5 

mtcars %>%  group_mean(cyl, am)

#    cyl    am   mpg  disp    hp  drat    wt  qsec    vs  gear  carb
#  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#1     4     0  22.9 136.   84.7  3.77  2.94  21.0 1      3.67  1.67
#2     4     1  28.1  93.6  81.9  4.18  2.04  18.4 0.875  4.25  1.5 
#3     6     0  19.1 205.  115.   3.42  3.39  19.2 1      3.5   2.5 
#4     6     1  20.6 155   132.   3.81  2.76  16.3 0      4.33  4.67
#5     8     0  15.0 358.  194.   3.12  4.10  17.1 0      3     3.08
#6     8     1  15.4 326   300.   3.88  3.37  14.6 0      5     6   

Upvotes: 6

Related Questions