Learning Ruby's inject (Enumerable) Method
Overview
I learned Ruby’s inject method by working through a problem. This is my note on it.
The Problem
Find the combination that breaks down 123,456 yen into the fewest possible bills and coins.
Coins … 1, 5, 10, 50, 100, 500 yen coins
Bills … 1000, 2000, 5000, 10000 yen bills
The Answer
- 10,000 yen bill × 12
- 5,000 yen bill × 0
- 2,000 yen bill × 1
- 1,000 yen bill × 1
- 500 yen coin × 0
- 100 yen coin × 4
- 50 yen coin × 1
- 10 yen coin × 0
- 5 yen coin × 1
- 1 yen coin × 1
The inject Method
By computing the answer as a combination held in an array, the code can be written simply.
Going from the largest denomination down, you append the result of divmod — [quotient, remainder] — onto the back of a growing array (a). Since r ends up holding the remainder (the last element of the array), you use it in the calculation of the next iteration.
1 | [] + 123456.divmode(10000) # [12, 3456] |
The trailing 0 is extra, but I was able to compute the answer in a very simple form.
That said,
my impression is that coming up with this inject expression off the bat takes some getting used to.
So
it seemed like a good way to get comfortable: first check the calculation steps with each, then try inject if it looks like the code can be made simpler.
The each Method
With each, you need to define the array to return at the very end — b = [] — outside the loop.
b << r if p.size - 1 == index is unnecessary, but I added it to make the resulting array match the inject version.
Taking a Benchmark
1 | require "benchmark" |
each was faster.
1 | user system total real |
Personally, this article would have wrapped up nicely if inject had come out faster, but with this particular calculation logic, each gave better performance.
Working with a Hash
inject
each
When I benchmarked it, each and hash were roughly equivalent.
Summary
I learned the inject method by working through an example problem.
In the example it could be written especially simply, but since it doesn’t dramatically improve performance, I felt you need to judge where it’s worth using.
That’s all.
I hope this is helpful.
