[1, 2, 3, 4].inject(0) { |result, element| result + element } # => 10
I\'m looking at this code but my brain is not registering how the number 1
[1, 2, 3, 4].inject(0) { |result, element| result + element } # => 10
In plain English, you are going through (iterating) through this array ([1,2,3,4]
). You will iterate through this array 4 times, because there are 4 elements (1, 2, 3, and 4). The inject method has 1 argument (the number 0), and you will add that argument to the 1st element (0 + 1. This equals 1). 1 is saved in the "result". Then you add that result (which is 1) to the next element (1 + 2. This is 3). This will now be saved as the result. Keep going: 3 + 3 equals 6. And finally, 6 + 4 equals 10.
Is the same as this:
[1,2,3,4].inject(:+)
=> 10
inject
takes a value to start with (the 0
in your example), and a block, and it runs that block once for each element of the list.
result + element
). The easiest way to explain this may be to show how each step works, for your example; this is an imaginary set of steps showing how this result could be evaluated:
[1, 2, 3, 4].inject(0) { |result, element| result + element }
[2, 3, 4].inject(0 + 1) { |result, element| result + element }
[3, 4].inject((0 + 1) + 2) { |result, element| result + element }
[4].inject(((0 + 1) + 2) + 3) { |result, element| result + element }
[].inject((((0 + 1) + 2) + 3) + 4) { |result, element| result + element }
(((0 + 1) + 2) + 3) + 4
10
tldr; inject
differs from map
in one important way: inject
returns the value of the last execution of the block whereas map
returns the array it iterated over.
More than that the value of each block execution passed into the next execution via the first parameter (result
in this case) and you can initialize that value (the (0)
part).
Your above example could be written using map
like this:
result = 0 # initialize result
[1, 2, 3, 4].map { |element| result += element }
# result => 10
Same effect but inject
is more concise here.
You'll often find an assignment happens in the map
block, whereas an evaluation happens in the inject
block.
Which method you choose depends on the scope you want for result
. When to not use it would be something like this:
result = [1, 2, 3, 4].inject(0) { |x, element| x + element }
You might be like all, "Lookie me, I just combined that all into one line," but you also temporarily allocated memory for x
as a scratch variable that wasn't necessary since you already had result
to work with.
It's just reduce
or fold
, if you're familiar with other languages.
There is another form of .inject() method That is very helpful [4,5].inject(&:+) That will add up all the element of the area