Why do I need to use .inject(0) rather than .inject to make this work? Why do I need to use .inject(0) rather than .inject to make this work? ruby-on-rails ruby-on-rails

Why do I need to use .inject(0) rather than .inject to make this work?


What we can read in API:

If you do not explicitly specify an initial value for memo, then uses the first element of collection is used as the initial value of memo.

So item_numbers[0] will be specified as an initial value - but it is not a number, it is an object. So we have got an error

undefined method `+'.

So we have to specify initial value as 0

item_numbers.inject(0){ |sum, i| sum + i }


It's because you are accessing i.amount as opposed to just plain i. In the version that doesn't work, you're implicitly doing item_numbers[0] + item_numbers[1].amount + ....

One shorthand would be item_numbers.map(&:amount).inject(&:+), but that way can result in two iterations over the list, if map doesn't return an enumerator.

If that didn't convince you, look at what gets printed out if we define a method amount on Fixnum that prints the value before returning it:

irb(main):002:1>   def amountirb(main):003:2>     puts "My amount is: #{self}"irb(main):004:2>     return selfirb(main):005:2>   endirb(main):006:1> end=> nilirb(main):007:0> [1,2,3].inject { |sum, i| sum + i.amount }My amount is: 2My amount is: 3=> 6irb(main):008:0> [1,2,3].inject(0) { |sum, i| sum + i.amount }My amount is: 1My amount is: 2My amount is: 3=> 6irb(main):009:0>

We can see clearly that amount is not called on the first element when a starting value is not explicitly passed in.


I was also banging my head against it some day, so I tried to visualize it. Hope it helps.enter image description here