4

I'm trying to write a function that takes as one of its arguments a vector of column names from user. The column names will be used to specify what columns of the dataframe will be pasted together to form a new column within dplyr::mutate. I tried to collapse the elements of argument vector first and then use the collapsed string in mutate - this is wrong. See that latest attempt below. I made other attempts but I'm not understanding the new quo, enquo, UQ, !!!, !!, and so on within dplyr. Can someone show what I need to do?

df <- data.frame(.yr = c("2000", "2001", "2002"), .mo = c("12", "01", "02"), .other = rnorm(3))
cols <- colnames(df)[1:2]

do_want <- df %>%
  mutate(new = paste(.yr, .mo, sep = "-"))

my_func <- function(dat, vars){
  .vars <- paste(vars, collapse = ",")

  result <- dat %>%
    mutate(new = paste(.vars, sep = "-" ))
  return(result)
}

my_func(dat = df, vars = cols)

edit: this is my attempt at using quo and !! in the function definition. the result is a column of repeated string ".yr,.mo"

my_func <- function(dat, vars){
  .vars <- quo(paste(vars, collapse = ","))

  result <- dat %>%
    mutate(new = paste(!!.vars, sep = "-" ))
  return(result)
}
Hong Ooi
  • 56,353
  • 13
  • 134
  • 187
bikeactuary
  • 447
  • 4
  • 18

3 Answers3

9

Because you have a list of strings, you can use rlang::syms in your function to take the strings and turn them into symbols. Then you can use !!! to splice the arguments together to put into paste.

my_func <- function(dat, vars){
     .vars <- rlang::syms(vars)

     result <- dat %>%
          mutate(new = paste(!!!.vars, sep = "-" ))
     return(result)
}

my_func(dat = df, vars = cols)

   .yr .mo     .other     new
1 2000  12 -0.2663456 2000-12
2 2001  01  0.5463433 2001-01
3 2002  02 -1.3133078 2002-02
aosmith
  • 34,856
  • 9
  • 84
  • 118
  • @Jelena-bioinf If you want to program with dplyr I don't know how to get around the exclamation points. See [here](https://dplyr.tidyverse.org/articles/programming.html) if you haven't already. You can definitely avoid if are working outside of dplyr or not writing functions, though! – aosmith Apr 18 '18 at 16:25
  • Yes, it `dplyr` is so beautiful when working outside the function. But when you need to do it in a function-based manner, it loses consistency and elegance.. – JelenaČuklina Apr 19 '18 at 09:32
1

Use unite.

names <- iris %>% colnames()
iris %>% mutate(new = paste(names)) #Error
iris %>% unite("new",names,remove=F) #OK
Takuro Ikeda
  • 158
  • 6
0

Use mutate_ instead of mutate & turning the expression into a string worked for me:

dplyr_solution <- function(dat, vars){
  .vars <- paste(vars, collapse = ",")

  result <- dat %>%
    mutate_(new = paste0('paste(', .vars, ', sep="-")'))
  return(result)
}

dplyr_solution(dat = df, vars = cols)
Z.Lin
  • 28,055
  • 6
  • 54
  • 94
  • Thank you - I had an attempt like this but did not wrap the inner paste in quotes. This works, still hoping someone can show a solution that utilizes the new rLang capability which makes mutate_ superfluous and is more elegant than 3 nested pastes. – bikeactuary Aug 15 '17 at 13:08
  • 3
    `mutate_` and the like are deprecated in dplyr now. – GcL Jan 30 '18 at 17:49