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