I am writing a function that combines a dplyr::filter
step (which I want to parametrize) before doing some other stuff. I want provide a default argument for the filtering criteria that can be overridden. This precludes passing the filtering arguments in with ...
One attempt, would be the following:
library(rlang)
library(dplyr)
filter_and_stuff1 = function(tbl, filter_args = list(mpg > 33, gear == 4), arg3, arg4){
as_expr = enexpr(filter_args)
sub_tbl = filter(tbl, !!!as_expr)
# do some other things with sub_tbl, arg3 and arg4
sub_tbl
}
But
filter_and_stuff1(mtcars)
Error: Argument 2 filter condition does not evaluate to a logical vector
It seems that the comma separation creates a problem. Looking inside dplyr's code, it's handled with a call to the internal function quo_reduce
, which seems to splice together the comma separated values with &
. I don't understand how to do this without use of ...
TLDR: How can I programmatically pass a set of arguments to dplyr::filter that includes a default expression?
The problem is that, with the way you're using it, enexpr
also captures the call to list
,
whereas using the ellipsis already separates each expression into different elements of a list:
library(rlang)
foo <- function(x) {
enexpr(x)
}
foo(list(a, b, c))
# list(a, b, c)
bar <- function(...) {
enexprs(...)
}
bar(a, b, c)
# [[1]]
# a
#
# [[2]]
# b
#
# [[3]]
# c
To do what you want, you can use call_args
to extract each expression from what was given to list
:
baz <- function(x) {
as_expr <- enexpr(x)
# expr just to show
expr(filter(!!!call_args(as_expr)))
}
baz(list(a == 1, b < 2))
# filter(a == 1, b < 2)