将参数向量列表作为 quosures 传递给具有 purrr 和 rlang 的函数

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

抱歉,标题中有很多介词。类似于 我有一个 quosures/arguments 的列表 我想传递给像 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

reprex package (v0.3.0.9001)

创建于 2020-09-02

使用 purrr 和 rlang,我如何将此列表的每个 quosure 传递给 count(mtcars, ...)

并执行

所以最终结果是相同的:

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

reprex package (v0.3.0.9001)

创建于 2020-09-02

难点在于此处使用了 c()。我们确实需要某种 rlang 对象来保存您的参数。这是生成列表的更改函数

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

这会获取您的表达式并评估它们将 c() 视为 enexprs()。然后你可以将这些值注入你的函数调用

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

如果您只是在列表中创建表达式而不使用 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))))

sort可以在外面

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