Everything I can find online about tidyeval is either older and not up to date with latest version of tidyverse\dplyr or else doesn't quite apply.
An example tibble is:
df <- tribble(
~var1, ~var2, ~var3,
1, 2, 3,
4, 5, 6,
7, 8, 9
)
I have a small function that I've written:
fun <- function(data, select_var, arrange_var) {
select_var <- enquo(select_var)
arrange_var <- enquo(arrange_var)
data %>%
select(!!select_var) %>%
arrange(!!arrange_var)
}
The function simply selects column(s) and then arranges by row(s).
When I pass the arguments to the function it works fine with a single variable inside of c():
fun(df,
c(var1,
var2)),
c(var2))
However, when I try to pass it two variables like this:
fun(df,
c(var1,
var2)),
c(var1,
var2))
I get the following error:
Error: incorrect size (282) at position 1, expecting : 141
The closest stack responses I've been able to find are: arrange() doesn't recognize column name parameter and Pass a vector of variable names to arrange() in dplyr
but both of these seem to give answers that included deprecated solutions (e.g., arrange_())
Some great information here: tidyeval resource roundup by Mara Averick
and Separating and Trimming Messy Data the Tidy Way by Paul Oldham
and of course I've dug into: tidyeval
However none of them seem to address this quirk. I've exhausted my resources after spending an afternoon. The code works find in a standard R file, just can't get it to work inside of a function, but about ready to give up, so thought I would see if you wonderful folks could help. Thanks in advance.
Update 2022/03/17
The tidyverse has evolved and so should this answer.
There is no need for enquo
anymore! Instead we enclose tidy-select expressions in double braces {{ }}
.
library("tidyverse")
df <- tribble(
~var1, ~var2, ~var3,
1, 2, 3,
4, 5, 6,
7, 8, 9
)
fun <- function(data, select_vars, ...) {
data %>%
select(
{{ select_vars }}
) %>%
arrange(
...
)
}
fun(df, c(var1, var2), desc(var2))
#> # A tibble: 3 × 2
#> var1 var2
#> <dbl> <dbl>
#> 1 7 8
#> 2 4 5
#> 3 1 2
fun(df, c(var1, var2), var1, var2)
#> # A tibble: 3 × 2
#> var1 var2
#> <dbl> <dbl>
#> 1 1 2
#> 2 4 5
#> 3 7 8
We still can't use c()
with the arrange
and filter
verbs because that's not allowed with data-masking.
df %>%
arrange(
c(var1, var2)
)
#> Error in `arrange()`:
#> ! Problem with the implicit `transmute()` step.
#> x Problem while computing `..1 = c(var1, var2)`.
#> x `..1` must be size 3 or 1, not 6.
Created on 2022-03-17 by the reprex package (v2.0.1)
Old answer
Replacing arrange_var
with ...
and specifying the variables without enclosing them in c()
makes it work.
library("dplyr")
df <- tribble(
~var1, ~var2, ~var3,
1, 2, 3,
4, 5, 6,
7, 8, 9
)
fun <- function(data, select_var, ...) {
select_var <- enquo(select_var)
data %>%
select(!!select_var) %>%
# You can pass the dots to `arrange` directly
arrange(...)
}
fun(df, c(var1, var2), var2)
#> # A tibble: 3 x 2
#> var1 var2
#> <dbl> <dbl>
#> 1 1 2
#> 2 4 5
#> 3 7 8
fun(df, c(var1, var2), var1, var2)
#> # A tibble: 3 x 2
#> var1 var2
#> <dbl> <dbl>
#> 1 1 2
#> 2 4 5
#> 3 7 8
Created on 2019-03-08 by the reprex package (v0.2.1)
It turns out that only select
supports strings and character vectors. As the documentation says, "This is unlike other verbs where strings would be ambiguous." See the last example for dplyr::select
.
# Two alternatives; both work with `select`.
df %>%
select(var1, var2)
#> # A tibble: 3 x 2
#> var1 var2
#> <dbl> <dbl>
#> 1 1 2
#> 2 4 5
#> 3 7 8
df %>%
select(c(var1, var2))
#> # A tibble: 3 x 2
#> var1 var2
#> <dbl> <dbl>
#> 1 1 2
#> 2 4 5
#> 3 7 8
# `arrange` only works with lists on comma separated unquoted variable names.
df %>%
arrange(var1, var2)
#> # A tibble: 3 x 3
#> var1 var2 var3
#> <dbl> <dbl> <dbl>
#> 1 1 2 3
#> 2 4 5 6
#> 3 7 8 9
df %>%
arrange(c(var, var2))
#> Error: incorrect size (4) at position 1, expecting : 3
Created on 2019-03-08 by the reprex package (v0.2.1)