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.