Array.first Vs Array.shift in Ruby
arrays, methods, ruby, shift
Solution
Just add one line `p acc` to debug it.
(arup~>~)$ pry --simple-prompt
>> module Enumerable
| def injecting(*acc, &block)
| acc = acc.empty? ? self.shift : acc.first
| p acc
| self.each do |x|
| acc = block.call(acc, x)
| end
| acc
| end
| end
=> nil
>> [1,2,3].injecting { |a,x| a + x }
1
=> 6
>>
When you called the method `injecting` on the array `[1,2,3]`, as `acc` was empty, `sef.shift` gets invoked. Now `acc` is `1`. Now `self` has only `[2,3]`. so the call `self.each..` first pass `2`, and then block gets invoked and the result of `a = x` is assigned to `acc`, whis now holds `3`. So now on the next iteration, from `self` next value passed(`3`), and block gets called again, and perform `a + x` again, so now value of `acc` is `6`. So you got the result `6`.
A one level more debugging :
(arup~>~)$ pry --simple-prompt
>> module Enumerable
| def injecting(*acc, &block)
| acc = acc.empty? ? self.shift : acc.first
| p "acc now holds #{acc}"
| p "elements in self is #{self}"
| self.each do |x|
| acc = block.call(acc, x)
| p "current value of acc is #{acc}"
| end
| acc
| end
| end
=> nil
>> [1,2,3].injecting { |a,x| a + x }
"acc now holds 1"
"elements in self is [2, 3]"
"current value of acc is 3"
"current value of acc is 6"
=> 6
>>
As per OP's comment
Am I safe assuming that by calling first, is still returning the 1st item but starts the iteration from that item, hence why I would get 7?
Again I would suggest you to add some debugging messages, to see what's going go under-hood. Look below :
(arup~>~)$ pry --simple-prompt
>> module Enumerable
| def injecting(*acc, &block)
| acc = acc.empty? ? self.first : acc.first
| p "acc now holds #{acc}"
| p "elements in self is #{self}"
| self.each do |x|
| acc = block.call(acc, x)
| p "current value of acc is #{acc}"
| end
| acc
| end
| end
=> nil
>> [1,2,3].injecting { |a,x| a + x }
"acc now holds 1"
"elements in self is [1, 2, 3]"
"current value of acc is 2"
"current value of acc is 4"
"current value of acc is 7"
=> 7
>>
`self.first` just returns the first element, which is `1`, and get assigned to `acc`. But self didn't get modified. But in case of `self.shift`, that `1` was assigned to `acc` and at the sane time got removed from `self`, and then `self` has `[2,3]`.
Now in this part, `self.each..` code passes 3 values of `self`, which are `1`,`2` and `3`. Now the summation is `6`, and added with `1`, which is the first `acc` value, when `self.first` got called. This is how the final result of `acc` is `7`.
Problem
I'm essentially going through an exercise for rewriting a basic form of the inject method from the Enumerable module and my solution was not doing anything as I was using #first: ``` def injecting(*acc, &block) acc = acc.empty? ? self.first : acc.first self.each do |x| acc = block.call(acc, x) end acc end ``` I then came across another solution which was using #shift instead of #first and was working just fine: ``` def injecting(*acc, &block) acc = acc.empty? ? self.shift : acc.first self.each do |x| acc = block.call(acc, x) end acc end ``` I know that #first returns the first element of the array but doesn't alter it while #shift returns and alters it, but I'm having a hard time understanding how the below code would still get the desired result if you were to mutate the array by dropping the first element: ``` [1,2,3].injecting { |a,x| a + x } # --> 6 ``` Any words of wisdom would be greatly appreciated.. Thanks!