I am a a bit confused by some of the behavior of the of the inject (alias reduce) command in Ruby
Background
For any array, the second element (referenced after the accumulator) reflects the last element in the array so
[1,2,10].inject{|accumulator,y| y}
gives 10
whereas the first element is the initial value of the array (that subsequently gets the result of any specified operation) if not otherwise specified so
[1,2,10].inject{|accumulator,y| accumulator}
gives 1
Addition
This results in the expected behavior for
[1,2,10].inject{|accumulator,y| accumulator + y}
gives 13
OR
[1,2,10].inject{|accumulator,y| y + accumulator}
gives 13
However,
If a string is used
["b","i","g"].inject{|x,y| y + x}
the result is "gib".
Why is it not "gbi"?
I would expect (last element + first element)+ i OR ("g"+"b")+ "i"
Subtraction
It also works as expected for subtraction when x is the value to be acted on first
[1,2,10].inject{|x,y| x - y}
gives -11 i.e (1-2) - 10 = -11 as expected
However,
when 'y' is the first element to be acted on
[1,2,10].inject{|x,y| y - x}
gives -9.
This is surprising. Only the last element and the first are used i.e 10-1.
Why is there is no accumulated result?!
I am a a bit confused by some of the behavior of the of the inject (alias reduce) command in Ruby
Background
For any array, the second element (referenced after the accumulator) reflects the last element in the array so
[1,2,10].inject{|accumulator,y| y}
gives 10
whereas the first element is the initial value of the array (that subsequently gets the result of any specified operation) if not otherwise specified so
[1,2,10].inject{|accumulator,y| accumulator}
gives 1
Addition
This results in the expected behavior for
[1,2,10].inject{|accumulator,y| accumulator + y}
gives 13
OR
[1,2,10].inject{|accumulator,y| y + accumulator}
gives 13
However,
If a string is used
["b","i","g"].inject{|x,y| y + x}
the result is "gib".
Why is it not "gbi"?
I would expect (last element + first element)+ i OR ("g"+"b")+ "i"
Subtraction
It also works as expected for subtraction when x is the value to be acted on first
[1,2,10].inject{|x,y| x - y}
gives -11 i.e (1-2) - 10 = -11 as expected
However,
when 'y' is the first element to be acted on
[1,2,10].inject{|x,y| y - x}
gives -9.
This is surprising. Only the last element and the first are used i.e 10-1.
Why is there is no accumulated result?!
1 Answer
Reset to default 3For any array, the second element (referenced after the accumulator) reflects the last element in the array
This incorrect statement is the source of the misunderstanding.
Look at the following code:
["b", "i", "g"].inject do |x, y|
puts({x: x, y: y, "y + x": (y + x) })
y + x
end
which prints
{x: "b", y: "i", "y + x": "ib"}
{x: "ib", y: "g", "y + x": "gib"}
As you can see, the second block parameter isn't the last element in the array, it's the next element in the array. ["b", "i", "g"].inject
uses "b"
as the first accumulator and passes "i"
, then "g"
.
[1,2,10].inject{|x,y| y - x}
gives -9
Are you sure? When I run that code, it returns 9
(which is 10 - (2 - 1)
). In any case, you can add the same puts
statement to observe how it proceeds.
inject
explain how it works. (hint: the block in your examples is called more than once) – Stefan Commented 10 hours ago