Let's try an example.
numbers = [ 3, 1, 4, 1, 5, 9 ]
sum = numbers.inject(0) do |prefix_sum, number|
prefix_sum + number
end
#inject takes one argument and a block. The block should take two values, and return a new value.
In the above example, the argument to #inject is 0, and the block is do |prefix_sum, number| prefix_sum + number end. The values that will be passed to the block are named in between the two | markers: prefix_sum and number.
Each value of the enumerable #inject was called on is passed as the second value to the block in turn. In this example number will be 3, then 1, then 4, then 1, then 5, then finally 9. So in this example, the block will be invoked six times; once for each position in numbers.
The first value passed to a block (here named prefix_sum) is usually called an accumulator. Its initial value, the value used the first time the block is called by #inject, is set by the argument passed to #inject (in this example, 0). The return value of the block determines the value of the accumulator (prefix_sum) for the next invocation of the block.
When there are no more elements to process, the value of the accumulator is returned (and here stored in sum).
So lets walk through it:
#inject receives 0 and our block.
#inject invokes our block, binding prefix_sum to 0 (the initial accumulator value) and number to 3 (the first array value).
- our block calculates
0+3 as 3 and returns it.
#inject invokes our block, binding prefix_sum to 3 (the returned value) and number to 1 (the second array value)
- our block calculates
3+1 as 4 and returns it.
#inject invokes our block, binding prefix_sum to 4 (the returned value) and number to 4 (the third array value)
- our block calculates
4+4 as 8 and returns it.
#inject invokes our block, binding prefix_sum to 8 (the returned value) and number to 1 (the fourth array value)
- our block calculates
8+1 as 9 and returns it.
#inject invokes our block, binding prefix_sum to 9 (the returned value) and number to 5 (the fifth array value)
- our block calculates
9+5 as 14 and returns it.
#inject invokes our block, binding prefix_sum to 14 (the returned value) and number to 9 (the sixth array value)
- our block calculates
14+9 as 23 and returns it.
- since there are no more array elements,
#inject returns 23, and we bind sum to be that value.
You can look at inject as parenthesizing an operation on a list of items, in this example, caluculating:
((((((0 + 3) + 1) + 4) + 1) + 5) + 9)
This lets you take any operation which normally only operates on a pair of arguments, and apply it to a list.