Array.first与Ruby中的Array.shift相同

时间:2014-02-01 17:57:26

标签: ruby arrays methods shift

我实际上正在进行一项练习,用于从Enumerable模块重写一个基本形式的inject方法,我的解决方案没有做任何事情,因为我正在使用#first:

def injecting(*acc, &block)
  acc = acc.empty? ? self.first : acc.first
  self.each do |x|
     acc = block.call(acc, x)
  end  
  acc
end

然后我遇到了另一个使用#shift而不是#first的解决方案,并且工作得很好:

def injecting(*acc, &block)
  acc = acc.empty? ? self.shift : acc.first
  self.each do |x|
    acc = block.call(acc, x)
  end  
  acc
end  

我知道#first返回数组的第一个元素,但是当#shift返回并改变它时不会改变它,但是我很难理解下面的代码如果仍然能得到想要的结果是通过删除第一个元素来改变数组:

[1,2,3].injecting { |a,x| a + x } # --> 6

任何智慧的话都会受到高度赞赏。

谢谢!

1 个答案:

答案 0 :(得分:4)

只需添加一行p acc即可进行调试。

(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
>> 

当您在数组injecting上调用方法[1,2,3]时,由于acc为空,因此会调用sef.shift。现在acc1。现在self只有[2,3]。所以调用self.each..首先通过2,然后调用块,a = x的结果分配给acc,现在保持3。所以现在在下一次迭代中,从self传递下一个值(3),再次调用块,再次执行a + x,所以现在acc的值为{ {1}}。所以你得到了结果6

更多级调试:

6

As per OP's comment

  

我安全地假设通过先调用,仍然返回第一项但是从该项开始迭代,因此为什么我会得到7?

我再次建议你添加一些调试信息,看看会发生什么事情。看下面:

(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
>>

(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,然后分配给1。但是自我没有得到修改。但是在acc的情况下,self.shift已被1分配给acc,并且在self已被删除,然后self[2,3] self.each.. }。

现在,在此部分中,self代码传递了1的3个值,即236。现在总和为1,并在调用acc时添加了self.first,这是第一个acc值。这就是7的最终结果是{{1}}。