Paul Lemmens
Paul Lemmens

Reputation: 625

Mimicking a secondary tidy dots argument in an R function

I'm looking to create a function that accepts a list of (data frame) variables as one of its parameters. I've managed to get it working partially, but when I get to the group_by/count, things fall apart. How can I do this??

## Works
f1 <- function(dfr, ..., split = NULL) {
  dots <- rlang::enquos(...)
  split <- rlang::enquos(split)
  dfr %>%
    select(!!!dots, !!!split) %>%
    gather('type', 'score', -c(!!!split))
}

## does not work
f2 <- function(dfr, ..., split = NULL) {
  dots <- rlang::enquos(...)
  split <- rlang::enquos(split)
  dfr %>%
    select(!!!dots, !!!split) %>%
    gather('type', 'score', -c(!!!split))
    count(!!!split, type, score)
  }

I would want to do things like

mtcars %>% f2(drat:qsec)
mtcars %>% f2(drat:qsec, split = gear)
mtcars %>% f2(drat:qsec, split = c(gear, carb)) ## ??

These calls with f1() all work, but for f2 none of the commands work. They all end up with a Error in !split : invalid argument type. That f2(drat:qsec) doesn't (immediately) work without the split argument, I'm not too surprised about, but how to get the second and third comment working?

Upvotes: 1

Views: 115

Answers (1)

lroha
lroha

Reputation: 34511

The issue with the second function (the missing pipe notwithstanding) is that count() (or rather group_by() which is called by count()) doesn't support tidyselect syntax so you can't pass it a list to be spliced like you can with select(), gather() etc. Instead, one option is to use group_by_at() and add_tally(). Here's a slightly modified version of the function:

library(dplyr)

f2 <- function(dfr, ..., split = NULL) {
  dfr %>%
    select(..., {{split}}) %>%
    gather('type', 'score', -{{split}}) %>%
    group_by_at(vars({{split}}, type, score)) %>% # could use `group_by_all()`
    add_tally()
}

mtcars %>% f2(drat:qsec)

# A tibble: 96 x 3
# Groups:   type, score [81]
   type  score     n
   <chr> <dbl> <int>
 1 drat   3.9      2
 2 drat   3.9      2
 3 drat   3.85     1
 4 drat   3.08     2
 5 drat   3.15     2
 6 drat   2.76     2
 7 drat   3.21     1
 8 drat   3.69     1
 9 drat   3.92     3
10 drat   3.92     3
# ... with 86 more rows

mtcars %>% f2(drat:qsec, split = c(gear, carb))

# A tibble: 96 x 5
# Groups:   gear, carb, type, score [89]
    gear  carb type  score     n
   <dbl> <dbl> <chr> <dbl> <int>
 1     4     4 drat   3.9      2
 2     4     4 drat   3.9      2
 3     4     1 drat   3.85     1
 4     3     1 drat   3.08     1
 5     3     2 drat   3.15     2
 6     3     1 drat   2.76     1
 7     3     4 drat   3.21     1
 8     4     2 drat   3.69     1
 9     4     2 drat   3.92     1
10     4     4 drat   3.92     2
# ... with 86 more rows

Upvotes: 1

Related Questions