I'm trying to make a calorie counter for the below hash menu. in this example I've passed 3 arguments - what would the function need to look like it the number of parameters/arguments is unknown?
@menu = {
"hamburger" => 250,
"Cheese burger" => 350,
"cola" => 35,
"salad" => 120,
"dessert" => 350
}
def order(a, b, c)
return @menu[a] @menu[b] @menu[c]
end
puts order("hamburger", "Cheese burger", "cola")
tried
def order(**a)
total = 0
total = @menu[**a]
end
i know (*a) works for arrays.
I'd like to be able to get results for puts order("hamburger") and equally for puts order("Cheese burger", "salad"), for example
CodePudding user response:
In Ruby, it is often possible to write the code exactly the same way you would describe the solution in English. In this case, you need to get the values at specific keys of the hash and then compute the sum of the values.
You can use the Hash#values_at
method to get the values at the specific keys and you can use the Array#sum
method to compute the sum of the values:
def order(*items)
@menu.values_at(*items).sum
end
Note that it is strange to use an instance variable of the top-level main
object. It would make much more sense to use a constant:
MENU = {
'hamburger' => 250,
'Cheese burger' => 350,
'cola' => 35,
'salad' => 120,
'dessert' => 350,
}
def order(*items)
MENU.values_at(*items).sum
end
It would also make sense to freeze
the hash:
MENU = {
'hamburger' => 250,
'Cheese burger' => 350,
'cola' => 35,
'salad' => 120,
'dessert' => 350,
}.freeze
And last but not least, I find the name of the order
method somewhat misleading. It is also ambiguous: is order
meant to be a noun and this is meant to be a getter method that retrieves an order? Or is it meant to be a verb and it is meant to be a command method which tells the object to execute an order?
Either way, it does not seem that the method is doing either of those two things, rather it seems to compute a total
. So, the name should probably reflect that.
CodePudding user response:
I would do:
MENU = {
"hamburger" => 250,
"Cheese burger" => 350,
"cola" => 35,
"salad" => 120,
"dessert" => 350
}
def order(*args)
MENU.values_at(*args).sum
end
order("hamburger", "Cheese burger", "cola")
#=> 635
Read about the Ruby Splat Operator, Hash#values_at
and Array#sum
.
When you really want to use each
(what I would not recommend), like mentioned in the comment, then you can implement it like this:
def order(*args)
total = 0
args.each { |name| total = MENU[name] }
total
end
or
def order(*args)
total = 0
MENU.values_at(*args).each { |value| total = value }
total
end