0

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)
23stacks1254
  • 369
  • 1
  • 9

1 Answers1

1
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.

Nick Kennedy
  • 12,510
  • 2
  • 30
  • 52
  • Thank you very much! I had been playing with it for a little while and couldn't get the quoting correct. I'll keep reviewing the resources you suggested. The use of ensyms is interesting to me and that mutate is called separately. I've been dragging my feet learning purrr::map and this will be a good example to study. Thank you! – 23stacks1254 Feb 20 '19 at 17:10