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.