evaluating optional argument using `rlang`

I am writing a custom function with arguments, some of which are compulsory and some optional. How can I use rlang to evaluate these arguments so that the function will work when-

  1. the optional arguments are not specified (and are, therefore, NULL)
  2. inputs are "quoted" or unquoted

Here is a minimal and reproducible example-

# setup
set.seed(123)
library(tidyverse)

# function to produce counts by groups
# `...` are other arguments used in the function somewhere else 
tryfn <- function(data, x, y = NULL, z = NULL, ...) {
  data %>%
    dplyr::group_by(.data = .,
                    !!rlang::enquo(x),
                    !!rlang::enquo(y),
                    !!rlang::enquo(z)) %>%
    dplyr::count() 
}

# works (unquoted arguments)
tryfn(ggplot2::mpg, drv, cyl, fl)
#> # A tibble: 22 x 4
#> # Groups:   drv, cyl, fl [22]
#>    drv     cyl fl        n
#>    <chr> <int> <chr> <int>
#>  1 4         4 p         8
#>  2 4         4 r        15
#>  3 4         6 d         1
#>  4 4         6 p         7
#>  5 4         6 r        24
#>  6 4         8 d         1
#>  7 4         8 e         6
#>  8 4         8 p         5
#>  9 4         8 r        36
#> 10 f         4 c         1
#> # ... with 12 more rows

# doesn't work (quoted arguments)
tryfn(ggplot2::mpg, "drv", "cyl", "fl")
#> # A tibble: 1 x 4
#> # Groups:   "drv", "cyl", "fl" [1]
#>   `"drv"` `"cyl"` `"fl"`     n
#>   <chr>   <chr>   <chr>  <int>
#> 1 drv     cyl     fl       234

# doesn't work (not specifying optional arguments)
tryfn(ggplot2::mpg, drv)
#> Error: Column `NULL` is unknown

Created on 2019-01-27 by the reprex package (v0.2.1)

Is this what you want?

library(magrittr)

f <- function(data, x, y = NULL, z = NULL) {
  dots <- rlang::enquos(x = x, y = y, z = z, .ignore_empty = "all")
  purrr::discard(dots, rlang::quo_is_null)
  
  data %>%
    dplyr::group_by_at(dots) %>%
    dplyr::count() 
}

f(ggplot2::mpg, "drv", "cyl", "fl")
#> # A tibble: 22 x 4
#> # Groups:   x, y, z [22]
#>    x         y z         n
#>    <chr> <int> <chr> <int>
#>  1 4         4 p         8
#>  2 4         4 r        15
#>  3 4         6 d         1
#>  4 4         6 p         7
#>  5 4         6 r        24
#>  6 4         8 d         1
#>  7 4         8 e         6
#>  8 4         8 p         5
#>  9 4         8 r        36
#> 10 f         4 c         1
#> # … with 12 more rows
f(ggplot2::mpg, drv)
#> # A tibble: 3 x 2
#> # Groups:   x [3]
#>   x         n
#>   <chr> <int>
#> 1 4       103
#> 2 f       106
#> 3 r        25

Created on 2019-01-31 by the reprex package (v0.2.1.9000)

4 Likes

This is beautiful! Thank you so much.

1 Like

Quick follow-up question: In its current implementation, the output df column names are x, y, z, etc. What if I wanted to preserve the original column names ("drv", "cyl", "fl") in the output data frame?

You can remove names.

rlang::enquos(x, y, z, .ignore_empty = "all")
1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.