Home > database >  R: passing character vector as a function parameter
R: passing character vector as a function parameter

Time:07-08

I'm new to R and am trying to learn how to create my own functions.

While the following function works fine:

#---------------------
# this works fine
#---------------------
func <- function(df) {
  
 new_df <- unite(df, key, c("Sepal.Length","Sepal.Width"), sep = " ", remove = FALSE, na.rm = FALSE)
 
 return(new_df)
 
}

new_iris <- func(iris)

, this function where the unite function's third argument is now parameterized:

#---------------------
# this does not work
#---------------------
func <- function(df, keycols) {
  
 new_df <- unite(df, key, keycols, sep = " ", remove = FALSE, na.rm = FALSE)
 
 return(new_df)
 
}

keycols <- quote(c("Sepal.Length","Sepal.Width"))

new_iris <- func(iris, keycols)

generates the following error message:

Error: Must subset columns with a valid subscript vector. x Subscript has the wrong type language. i It must be numeric or character.

Is there a way to pass c("Sepal.Length","Sepal.Width") as a parameter? Or some way to make the keycols a parameter for the above user defined function?

Thanks for any guidance.

CodePudding user response:

You may adopt either of these methods

library(tidyr)
func <- function(df, ...){
  unite(df, key, ..., sep=" ", remove = FALSE, na.rm = FALSE)
}

func(iris, Sepal.Length, Sepal.Width)
#>         key Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
#> 1   5.1 3.5          5.1         3.5          1.4         0.2     setosa
#> 2     4.9 3          4.9         3.0          1.4         0.2     setosa
#> 3   4.7 3.2          4.7         3.2          1.3         0.2     setosa



keycols <- c("Sepal.Length", "Sepal.Width")

func <- function(df, cols){
  unite(df, key, !!cols, sep=" ", remove = FALSE, na.rm = FALSE)
}

func(iris, keycols)
#>         key Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
#> 1   5.1 3.5          5.1         3.5          1.4         0.2     setosa
#> 2     4.9 3          4.9         3.0          1.4         0.2     setosa
#> 3   4.7 3.2          4.7         3.2          1.3         0.2     setosa
#> 4   4.6 3.1          4.6         3.1          1.5         0.2     setosa

Created on 2022-07-08 by the reprex package (v2.0.1)

CodePudding user response:

One way you could achieve this simply by using curly-curly {{}} from rlang package which is a safe option,

library(tidyr)
library(rlang)

iris <- tibble::as_tibble(iris)


# using curly curly from {rlang} ------------------------------------------

func <- function(df, keycols) {
  
  new_df <- unite(df, "key", {{keycols}}, sep = " ", remove = FALSE, na.rm = FALSE)
  
  return(new_df)
  
}

func(iris, c(Sepal.Length, Sepal.Width)) # passing directly the columns

#> # A tibble: 150 × 6
#>    key     Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#>    <chr>          <dbl>       <dbl>        <dbl>       <dbl> <fct>  
#>  1 5.1 3.5          5.1         3.5          1.4         0.2 setosa 
#>  2 4.9 3            4.9         3            1.4         0.2 setosa 
#>  3 4.7 3.2          4.7         3.2          1.3         0.2 setosa 
#>  4 4.6 3.1          4.6         3.1          1.5         0.2 setosa 
#>  5 5 3.6            5           3.6          1.4         0.2 setosa 
#>  6 5.4 3.9          5.4         3.9          1.7         0.4 setosa 
#>  7 4.6 3.4          4.6         3.4          1.4         0.3 setosa 
#>  8 5 3.4            5           3.4          1.5         0.2 setosa 
#>  9 4.4 2.9          4.4         2.9          1.4         0.2 setosa 
#> 10 4.9 3.1          4.9         3.1          1.5         0.1 setosa 
#> # … with 140 more rows

func(iris, c("Sepal.Length", "Sepal.Width")) # passing columns as character vector

#> # A tibble: 150 × 6
#>    key     Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#>    <chr>          <dbl>       <dbl>        <dbl>       <dbl> <fct>  
#>  1 5.1 3.5          5.1         3.5          1.4         0.2 setosa 
#>  2 4.9 3            4.9         3            1.4         0.2 setosa 
#>  3 4.7 3.2          4.7         3.2          1.3         0.2 setosa 
#>  4 4.6 3.1          4.6         3.1          1.5         0.2 setosa 
#>  5 5 3.6            5           3.6          1.4         0.2 setosa 
#>  6 5.4 3.9          5.4         3.9          1.7         0.4 setosa 
#>  7 4.6 3.4          4.6         3.4          1.4         0.3 setosa 
#>  8 5 3.4            5           3.4          1.5         0.2 setosa 
#>  9 4.4 2.9          4.4         2.9          1.4         0.2 setosa 
#> 10 4.9 3.1          4.9         3.1          1.5         0.1 setosa 
#> # … with 140 more rows

Created on 2022-07-08 by the reprex package (v2.0.1)

To understand why and how this solution works, look here programming with dplyr

  •  Tags:  
  • r
  • Related