Reputation: 403
I wonder how to think about making R functions flexible to different types of input such as vectors, lists, dataframes and tibbles. Please see examples below. And specifically wonder:
Are there better approaches to this? Are there different aspects that are important to think about when addressing this problem?
# Example data
x <- c(1, 2)
y <- c(1, 2)
# Example function
add_numbers <- function(x, y){
z <- x+y
z
}
add_numbers(x, y)
# They function does not work with lists as input!
x_list <- list(c(1, 2))
y_list <- list(c(1, 2))
add_numbers(x_list, y_list)
# The 2 examples below works, but provide different names for column in output.
x_tb <- tibble::as_tibble_col(c(1, 2))
y_tb <- tibble::as_tibble_col(c(1, 2))
z_tb <- add_numbers(x_tb, y_tb)
z_tb$value # Note the column name is different in output
x_df <- as.data.frame(c(1, 2))
y_df <- as.data.frame(c(1, 2))
z_df <- add_numbers(x_df, y_df)
z_df$`c(1, 2)` # Note the column name is different in output
# Potential solution for a more flexibl function
add_numbers_flexible <- function(x, y) {
# If vec make tibble
if(is.vector(x) && length(x)>1) {
x <- tibble::as_tibble_col(x)
}
if(is.vector(y) && length(y)>1) {
y <- tibble::as_tibble_col(y)
}
# Sort out if input is list
if(is.list(x)){
x <- tibble::as_tibble_col(x[[1]])
}
if(is.list(y)){
y <- tibble::as_tibble_col(y[[1]])
}
# Sort out if input is data.frame
if(is.data.frame(x)){
colnames(x) <- "value"
}
if(is.data.frame(y)){
colnames(y) <- "value"
}
z <- x+y
z
}
# These now works, providing similar output
add_numbers_flexible(x, y)
add_numbers_flexible(x_list, y_list)
add_numbers_flexible(x_df, y_df)
add_numbers_flexible(x_tb, y_tb)
Upvotes: 1
Views: 136
Reputation: 2541
For this particular example, unlist
ing each object before adding would work for all example use cases.
x <- c(1, 2); y <- c(1, 2)
x_list <- list(c(1, 2)); y_list <- list(c(1, 2))
x_tb <- tibble::as_tibble_col(c(1, 2)); y_tb <- tibble::as_tibble_col(c(1, 2))
x_df <- as.data.frame(c(1, 2)); y_df <- as.data.frame(c(1, 2))
add_numbers_flex2 <- function(x, y) {
x2 <- unlist(x)
y2 <- unlist(y)
return(x2 + y2)
}
add_numbers_flex2(x,y)
#> [1] 2 4
add_numbers_flex2(x_list, y_list)
#> [1] 2 4
add_numbers_flex2(x_tb, y_tb)
#> value1 value2
#> 2 4
add_numbers_flex2(x_df, y_df)
#> c(1, 2)1 c(1, 2)2
#> 2 4
In fact, it would even work by mixing types, though I'm not sure weather that's desirable:
add_numbers_flex2(x_df, y)
#> c(1, 2)1 c(1, 2)2
#> 2 4
Upvotes: 1