Considering that a total cost
is being calculated, it appears that @menu
contains unit prices (as one generally finds, except perhaps at the very best restaurants) and each order contains the number of each menu item that is ordered. Suppose:
@menu = {rice: 0.69, noodles: 0.89}
where the values are unit prices and an element of orders
looks something like this:
{rice: 3, noodles: 2}
where the values are quantities ordered. The cost to supply the quantities given by this order would be:
(3)(0.69) + (2)(0.89) = 3.95
You are to sum this cost over all orders.
First, let's write the method like this,
def cost( *orders )
orders.inject(0) do |total_cost, order|
total_cost + order.keys.inject(0) do |cost, key|
cost + order[key] * @menu[key]
end
end
end
to clarify its structure. inject
(aka reduce
) is iterating over orders
and accumulating a value in the variable total_cost
. You can assign total_cost
an initial value by passing an argument to inject
(as you have done). If you don't give inject
an argument initial value, total_cost
is set equal to the first evaluated value in the block that follows inject
. In this case, you would get the same results if you dropped the arguments to inject
.
For the first value of orders
(the block variable order
), the following number is added to the accumulator total_cost
:
order.keys.inject(0) do |cost, key|
cost + @menu[key] * order[key]
end
To obtain this value, Ruby must perform a side calculation. Suppose @menu
and order
have the values I gave above.
inject(0)
iterates over order.keys
(which is [:rice, :noodles]
), using cost
as its accumulator. The block is executed for :rice
and then for noodles
:
cost + order[:rice] * @menu[:rice] => 0 + 3 * 0.69 # => 2.07 => cost
cost + order[:noodles] * @menu[:noodles] => 2.07 + 2 * 0.89 # => 3.95 => cost
This completes the side calculation, so 3.95 is added to the outer accumulator total_cost
(which previously equaled zero). The next element of orders
is then processed by the outer inject
, and so on.