Pass vector of column names to paste() within mutate (dplyr)
Asked Answered
L

3

5

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)
}
Laidlaw answered 15/8, 2017 at 3:56 Comment(0)
D
10

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
Displease answered 15/8, 2017 at 15:18 Comment(2)
@Jelena-bioinf If you want to program with dplyr I don't know how to get around the exclamation points. See here if you haven't already. You can definitely avoid if are working outside of dplyr or not writing functions, though!Displease
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..Filip
S
2

Use unite.

names <- iris %>% colnames()
iris %>% mutate(new = paste(names)) #Error
iris %>% unite("new",names,remove=F) #OK
Skycap answered 16/10, 2020 at 6:35 Comment(0)
I
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)
Insnare answered 15/8, 2017 at 8:34 Comment(2)
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.Laidlaw
mutate_ and the like are deprecated in dplyr now.Nannettenanni

© 2022 - 2025 — McMap. All rights reserved.