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!

Original source