2017-09-08 75 views
0
a = ['red', 'green', 'blue', 'purple'] 

a.each do |e| 
puts e 
if e == 'green' 
    a.delete(e) 
end 
end 

通过运行上面的代码,我得到以下的输出:红宝石删除数组元素,而迭代

red 
green 
purple 

有人能向我解释发生了什么幕后?

+0

不,你应该得到的“红,蓝,紫”。什么是你使用的Ruby版本? – Mohanraj

+2

我正在使用ruby 2.3.3p222。无论如何,我正在删除后,所以'绿色'应该打印任何方式。我想知道'蓝'是如何跳过的? –

+0

是的你是对的。 – Mohanraj

回答

5

这是的一部分。]实施each

for (i=0; i<RARRAY_LEN(ary); i++) { 
    rb_yield(RARRAY_AREF(ary, i)); 
} 
return ary; 

所以简单地移动沿着阵列的“读头”,直到它到达终点。

当您删除"green"时,阵列的元素将被移位以取代它的位置,并且"blue"现在是绿色所在的位置。但是我们已经阅读了这个位置的元素。下一个要读取的元素是紫色的。

这正是为什么你不应该改变你正在迭代的集合(除非这个效果是你真正想要的)。

我无法理解的本地代码

这里是一个“读头”的心理模型的可视化一点。

v 
red green blue purple # print red 

# next 

     v 
red green blue purple # print green 

    v 
red blue purple # delete green in the same iteration 

# next 

      v 
red blue purple # print purple 
+0

甚至在模块完成执行之前就进行了转换? 其实,我不明白本机代码:( 你可以写一个伪代码吗? –

+0

@AkashCP这个转换是在'delete'返回之前进行的,是的。 –

3

为了增加Sergio的解释,更惯用的方法来修改阵列将是:

a = ['red', 'green', 'blue', 'purple'] 
a.reject! do |e| 
    puts e 
    e == 'green' 
end 

这样:

2.2.5 :001 >  a = ['red', 'green', 'blue', 'purple'] 
=> ["red", "green", "blue", "purple"] 
2.2.5 :002 >  a.reject! do |e| 
2.2.5 :003 >   puts e 
2.2.5 :004?>   e == 'green' 
2.2.5 :005?>  end 
red 
green 
blue 
purple 
=> ["red", "blue", "purple"] 
2.2.5 :006 >