ELI5: how does rlang work with lapply()?

dplyr
tidyeval
tidyverse

#1

I’m struggling to understand how to use lapply() in conjunction with rlang. I know how to do this in base R and with the old group_by_(), but I don’t understand rlang well enough to make this work.

All I want to do is iterate a function over a list of variable names. I don’t care whether the names are quoted or not. But I want to do it in a tidyverse way.

Here is what I’ve tried:

library(tidyverse)
library(rlang)
my_fun <- function(data, var) {
  my_var <- enquo(var)
  data %>%
    filter((!!my_var) == 1) %>%
    summarize(N = n(), 
              mean_value = mean(mpg, na.rm = TRUE))
}
my_fun(mtcars, am)

I sort of understand why this doesn’t work:

# names(mtcars) is already quoted
lapply(names(mtcars), my_fun, data = mtcars)

But how do I lapply() over a list of variable names?

UPDATE: A colleague made this work with the following modifications:

library(tidyverse)
library(rlang)

my_fun <- function(data, var) {
  my_var <- var
  data %>%
    filter(UQS(my_var) == 1) %>%
    summarize(N = n(), 
              mean_value = mean(mpg, na.rm = TRUE))
}
names_prep <- lapply(names(mtcars), parse_quosure)
list_result <- lapply(names_prep, my_fun, data = mtcars)

But:

  • I still don’t understand
  • This seems way too hard for what I am trying to do. Is this a more elegant solution?
  • I’m an educator so I need to be able to explain this code to relative novices. How is this approach superior to the base R approach?

P.S. - I know this example doesn’t make practical sense.


#2

Does this help?

library(rlang)

vars <- syms(names(mtcars)[1:3])
lapply(vars, function(x) expr(mean(!!x, na.rm = TRUE)))
#> [[1]]
#> mean(mpg, na.rm = TRUE)
#> 
#> [[2]]
#> mean(cyl, na.rm = TRUE)
#> 
#> [[3]]
#> mean(disp, na.rm = TRUE)

If you could outline your real problem a bit more I could provide more hints - but in most cases it’s a matter of capturing the variance names correctly, then combining lapply()/map() + expr(). (And if the environment is important, replace expr with quo)


#3

This is the sort of syntax that would be nice to see abstracted into rlang. Specifically, if you took the body of functions that manipulate between a single expr, name, string, quosure and created a version that could handle a list of expr, names, strings, quosures that would really help. Some of the most basic functions like quos and UQS are there but there’s no quos_expr.