Home > Net >  How to pass sets of inputs variables to a function in R?
How to pass sets of inputs variables to a function in R?

Time:07-30

Good day,

I am trying to learn how to easily feed various sets of inputs to a function. Each set of input is like the characteristics of an object. The function should be able to run calculations given the choice of objects and accept other arguments too.

Let's illustrate this with a simplified example about groceries.

The function basket() can accept fruits that have a value and a sugar_amount. I can decide to place any number of fruits in the basket, and I want to return the total value and the sugar amount.

The function basket() should retrieve each fruit's value and sugar_amount from a dataframe or an external CSV file, for example. This data could be structured in this way:

        value  sugar_amount
APPLE      10            20
BANANA      5            10 
CHERRY     15            25

The function can accept several combinations of fruits, allowing the user to pick up to three fruits in our example (the number of available fruits), but can decide to select one or two kinds. The user can also specify how many of each fruit he wants to put in his basket (n1 for the first fruit, n2 for the second, and so on).

basket <- function (fruit1, n1,
                    fruit2, n2,
                    fruit3, n3) {
   total_value = (fruit1$value * n1)   (fruit2$value * n2)   (fruit3$value * n3)
   total_sugar = (fruit1$sugar_amount* n1)   (fruit2$sugar_amount* n2)   (fruit3$sugar_amount* n3)
   }

An example calculation would be:

mix1 <- basket(APPLE, n1 = 1, CHERRY, n2 = 2)

      total_value  total_sugar   
mix1           40           70

As you can tell, this would not work as such since it is what I am trying to understand... What should I do to have the possibility of calling any fruit combination I want? Something related with do.call()?

If to go a bit further, I also wondered how to feed several sets of inputs to a function. Is it possible to use a list of mixes and use a sort of lapply() function to achieve this:

      total_value  total_sugar   
mix1           40           70
mix2           60           15
mix3           20           50

(Given that each mix is a different combination and quantity of fruits)

This is all new to me and I have not found an answer online so far. Thanks a lot for your support!

CodePudding user response:

It sounds like you just need to understand how vectorized and list-wise functions work in R. See here for examples that can help.

However, to directly address your question, we could implement what you want per below.

Get rows from data.frame based on vector of values

library(dplyr)

# Create your underlying "database"
df <- data.frame(
  fruit = c("apple", "banana", "cherry"),
  value = c(10, 5, 15),
  sugar_amount = c(20, 10, 25)
)

# Create a function that takes a *vector* of fruit names and returns the
# value and sugar amount. Length of vector doesn't matter.
basket <- function(database, fruit_vector) {
  # Subset database to matching fruit
  database %>%
    filter(fruit %in% fruit_vector)
}

# Pass it two fruits found in the database
basket(df, c("apple", "cherry"))
#>    fruit value sugar_amount
#> 1  apple    10           20
#> 2 cherry    15           25

# Pass it 1 fruit in the database and 2 NOT in the database
basket(df, c("apple", "kiwi", "grape"))
#>   fruit value sugar_amount
#> 1 apple    10           20

Use vectors to operate on a data.frame

# Create a function that takes a vector of fruits and an
# equal-length vector of quantities to produce functions
# of those quantities and database values for the fruits
# specified in the vector
compute_totals <- function(database, fruits, quantity) {
  # Stop and report error if fruits and quantity aren't same length
  if (length(fruits) != length(quantity)) {
    stop("Fruits and quantity must be same length.")
  }
  
  # Build a data.frame from arguments
  inputs <- data.frame(fruit = fruits, quantity = quantity)
  
  # Add value and sugar amount to it
  joined <- left_join(inputs, database, by = "fruit")
  
  # Calculate total sugar and total value by fruit
  by_fruit <- joined %>%
    transmute(
      fruit = fruits,
      total_sugar = quantity * sugar_amount,
      total_value = quantity * value
    )
  
  # We can store that in a list for the output, as well
  # as get the totals for the mix and store it in the list
  # so our function returns both
  by_mix <- by_fruit %>%
    summarise(total_sugar = sum(total_sugar),
              total_value = sum(total_value))
  
  # Store in and return list
  list(by_fruit, by_mix)
  
}

# Examples - typical use
compute_totals(df, c("apple", "banana"), c(2, 3))
#> [[1]]
#>    fruit total_sugar total_value
#> 1  apple          40          20
#> 2 banana          30          15
#> 
#> [[2]]
#>   total_sugar total_value
#> 1          70          35
compute_totals(df, "cherry", 100)
#> [[1]]
#>    fruit total_sugar total_value
#> 1 cherry        2500        1500
#> 
#> [[2]]
#>   total_sugar total_value
#> 1        2500        1500

# Demonstrate error message by passing 2 fruits, 3 quantities
compute_totals(df, c("apple", "banana"), c(2, 3, 4))
#> Error in compute_totals(df, c("apple", "banana"), c(2, 3, 4)): Fruits and quantity must be same length.
  • Related