23stacks1254
23stacks1254

Reputation: 389

How to pass a list of of variables to a function but also considering quosures and quoting

I'd like to pass a list of variables to a function, but I'm confused by the quoting and quosures.

Normally, I want to return a df after some kind of data management has been done--after the function has been applied to several variables.

As it is the function works ok (just slightly modified from a users stack exchange answer to another question), but the calls are repetitive in this example. Any suggestions, points to readings or etc., I'd appreciate.

library(tidyverse)
library(rlang)
library(tidyselect)

data <- data.frame(ageeeeoo = c(1,NA,3,NA,5), 
                   ageeeaah = c(NA,2,NA,4,NA),
                   numnumd  = c(1,NA,3,NA,5),
                   numfoofe = c(NA,2,NA,4,NA))



newfun <- function (var1) {

var1<-enquo(var1)
data<<-mutate(data,(!!as_name(var1)) := coalesce(!!! syms(vars_select(names(data), 
                                       starts_with(as_name(var1))))))
}


newfun(age)
newfun(num)



  ageeeeoo ageeeaah numnumd numfoofe age num
        1       NA       1       NA   1   1
       NA        2      NA        2   2   2
        3       NA       3       NA   3   3
       NA        4      NA        4   4   4
        5       NA       5       NA   5   5

I tried reviewing the dplyr programming documents and a few other stack exchange QA but the quoting throws me off. I've tried using alist and list but get errors.

listofvars<-c("age","num")

newfun <- function (...) {

data<<-mutate(data,(!!!rlang::syms(...)) := coalesce(!!! syms(vars_select(names(data),
                                            starts_with(!!!quos(...))))))
}


  newfun(listofvars)

Upvotes: 0

Views: 163

Answers (1)

Nick Kennedy
Nick Kennedy

Reputation: 12640

library(tidyverse)
library(rlang)
library(tidyselect)

data <- data.frame(ageeeeoo = c(1,NA,3,NA,5), 
                   ageeeaah = c(NA,2,NA,4,NA),
                   numnumd  = c(1,NA,3,NA,5),
                   numfoofe = c(NA,2,NA,4,NA))



newfun2 <- function (data, ...) {

  vars <- ensyms(..., .named = TRUE)
  needed <- map(
    vars,
    ~vars_select(names(data), starts_with(as_name(.x))) %>% 
    {quo(coalesce(!!!syms(.)))}
  )
  mutate(data, !!!needed)
}

data <- newfun2(data, age, num)

list_of_vars <- exprs(age, num)
data <- newfun2(data, !!!list_of_vars)
data

This first captures the input from ... as symbols. It can uses purrr::map to generate a list of coalesce operations. These are then supplied to mutate. I’ve rewritten the code so as not to modify the global environment within a function; most R code works like this, so in general variables won’t be altered except by explicit assignment.

The rlang help and Hadley Wickham’s advanced R are great resources.

Upvotes: 1

Related Questions