David Ranzolin
David Ranzolin

Reputation: 1074

Pass a list of vectors of arguments as quosures to a function with purrr and rlang

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)

Upvotes: 0

Views: 305

Answers (2)

MrFlick
MrFlick

Reputation: 206167

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))))

Upvotes: 2

akrun
akrun

Reputation: 886928

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

Upvotes: 2

Related Questions