The Enumerable#each_with_object
method behaves very similarly to Enumerable#inject
! There are only a couple of differences!
The block arguments are reversed
The inject
method passes the block arguments in the following order:
- The
accumulator
which is initially the object thatinject
was called with - The value/object for each member in the
Enumerable
thatinject
was called on
For the example below, subtotal
is the accumulator
and item
is the value/object.
@order.line_items.inject(0) |subtotal, item|
subtotal + (item.quantity * item.price)
end
The arguments are the same with each_with_object
but just in the reverse order!
The initial object is always returned
While inject
allows you to perform some logic within a block and return a new accumulator
object with each iteration, the each_with_object
method always returns the initial object that it was called with.
This is useful in cases where the initial object is mutated each iteration.
quantities = LineItem.for_orders_today.each_with_object({}) |item, hash|
hash[item.name] ||= 0
hash[item.name] += item.quantity
end
Compare that to the inject
equivalent!
quantities = LineItem.for_orders_today.inject({}) |hash, item|
hash[item.name] ||= 0
hash[item.name] += item.quantity
hash
end