0

Sorry for the numerous prepositions in the title. Similar to this question, I have a list of quosures/arguments I want to pass to a function like dplyr::count:

library(rlang)
suppressPackageStartupMessages(library(dplyr))

q_list <- function(...) {
  enquos(...)
}

my_q_list <- q_list(
  c(cyl, sort = TRUE),
  c(cyl, gear, sort = TRUE)
)
my_q_list
#> <list_of<quosure>>
#> 
#> [[1]]
#> <quosure>
#> expr: ^c(cyl, sort = TRUE)
#> env:  global
#> 
#> [[2]]
#> <quosure>
#> expr: ^c(cyl, gear, sort = TRUE)
#> env:  global

Created on 2020-09-02 by the reprex package (v0.3.0.9001)

Using purrr and rlang, how do I pass and execute each quosure of this list to count(mtcars, ...)

So the end result is identical to:

suppressPackageStartupMessages(library(dplyr))
count(mtcars, cyl, sort = TRUE)
#>   cyl  n
#> 1   8 14
#> 2   4 11
#> 3   6  7
count(mtcars, cyl, gear, sort = TRUE)
#>   cyl gear  n
#> 1   8    3 12
#> 2   4    4  8
#> 3   6    4  4
#> 4   4    5  2
#> 5   6    3  2
#> 6   8    5  2
#> 7   4    3  1
#> 8   6    5  1

Created on 2020-09-02 by the reprex package (v0.3.0.9001)

David Ranzolin
  • 913
  • 1
  • 6
  • 18

2 Answers2

2

The thing that makes this difficult is the use of c() here. We really need some sort of rlang object to hold your parameters. Here's an altered function to generate your list

q_list <- function(...) {
  q <- enexprs(...)
  transenv <- new_environment(list(c=exprs))
  purrr::map(q, function(x) {
    eval_tidy(x, env = transenv)
  })
}

This takes your expressions and evaulates them treating c() like enexprs(). Then you can inject those values into your function call

my_q_list <- q_list(
  c(cyl, sort = TRUE),
  c(cyl, gear, sort = TRUE)
)

purrr::map(my_q_list, ~eval_tidy(quo(count(mtcars, !!!.x))))

This would have been easier if you just make the expressions in a list without using c()

my_q_list <- list(
  exprs(cyl, sort = TRUE),
  exprs(cyl, gear, sort = TRUE)
)
purrr::map(my_q_list, ~eval_tidy(quo(count(mtcars, !!!.x))))
MrFlick
  • 195,160
  • 17
  • 277
  • 295
  • Interesting, this mostly works, but sort = TRUE is evaluated to mutate another column, not as the sort argument to count. – David Ranzolin Sep 02 '20 at 23:37
  • @DavidRanzolin I did miss that. I'm kind of surprised by that. I've updated to use a workaround. I'll keep looking to see why that's the case. – MrFlick Sep 03 '20 at 00:16
  • Yes, I think it's related, but I was surprised select(mtcars, c(cyl, carb)) works fine but count(mtcars, c(cyl, carb)) fails. – David Ranzolin Sep 03 '20 at 03:09
2

The sort can be outside

library(purrr)
list(q_list(cyl), q_list(cyl, gear)) %>% 
  map(~ count(mtcars, !!! .x, sort = TRUE))
#[[1]]
#  cyl  n
#1   8 14
#2   4 11
3   6  7

#[[2]]
#  cyl gear  n
#1   8    3 12
#2   4    4  8
#3   6    4  4
#4   4    5  2
#5   6    3  2
#6   8    5  2
#7   4    3  1
#8   6    5  1
akrun
  • 874,273
  • 37
  • 540
  • 662