Thomas Price
Thomas Price

Reputation: 101

Get all combinations of a character vector

I am trying to write a function to dynamically group_by every combination of a character vector.

This is how I set it up my list:

stuff <- c("type", "country", "color")
stuff_ListStr <- do.call("c", lapply(seq_along(stuff), function(i) combn(stuff, i, FUN = list)))
stuff_ListChar <- sapply(stuff_ListStr, paste, collapse = ", ")
stuff_ListSym <- lapply(stuff_ListChar, as.symbol)

Then I threw it into a loop.

b <- list()
for (each in stuff_ListSym) {
  a <- answers_wfh %>% 
    group_by(!!each) %>% 
    summarize(n=n())
  b <- append(b, a)
}

So essentially I want to replicate this

...     group_by(type),

...     group_by(country),

...     group_by(type, country), 

... and the rest of the combinations. Then I want put all the summaries into one list (a list of tibbles/lists)

It's totally failing. This is my error message: Error: Column `type, country` is unknown.

Not only that, b is not giving me what I want. It's a list with length 12 already when I only expected 2 before it failed. One tibble grouped by 'type' and the second by 'country'.

I'm new to R in general but thought tidy eval was really cool and wanted to try. Any tips here?

Upvotes: 0

Views: 178

Answers (2)

Ronak Shah
Ronak Shah

Reputation: 389165

I think stuff_ListStr is enough to get what you want. You cold use group_by_at which accepts character vector.

library(dplyr)
library(rlang)

purrr::map(stuff_ListStr, ~answers_wfh %>% group_by_at(.x) %>% summarize(n=n()))

A better option is to use count but count does not accept character vectors so using some non-standard evaluation.

purrr::map(stuff_ListStr, ~answers_wfh %>% count(!!!syms(.x)))

Upvotes: 1

linog
linog

Reputation: 6226

I think you have a problem of standard evaluation. !! is sometimes not enough to unquote variables and get dplyr to work. Use !!! and rlang::syms for multiple unquotes

b <- list()
for (each in stuff_ListSym) {
  a <- answers_wfh %>% 
    group_by(!!!rlang::syms(each)) %>% 
    summarize(n=n())
  b <- append(b, a)
}

I think lapply would be better in your situation than for since you want to end-up with a list

Since you use variable names as arguments of functions, you might be more comfortable with data.table than dplyr. If you want the equivalent data.table implementation:

library(data.table)
setDT(answers_wfh)
lapply(stuff_ListSym, function(g) answers_wfh[,.(n = .N), by = g])

You can have a look at this blog post I wrote on the subject of SE vs NSE in dplyr and data.table

Upvotes: 3

Related Questions