7

我正在尝试以下代码:

a = [1,2,3,4]  
a.each do  
  puts "Removing #{a.last}"  
  a.pop  
end

但是我没有弹出所有四个数字,而是只得到前 3 个。确实,执行 puts a.length 之类的操作会返回 1 并且 puts-ing 它显示元素“1”仍然存在。

如何正确使用该方法?(我使用的是 Ruby 2.0)。

4

6 回答 6

7

我怀疑这是因为您在修改列表时迭代列表的元素。

尝试以下操作:

a = [1,2,3,4]
until a.empty? do
  puts "Removing #{a.last}"
  a.pop
end
于 2013-05-10T08:24:31.580 回答
3

问题
当您迭代时,a您正在更改它。

问题的解释
这意味着一旦你删除了一个元素,每个方法都会被抛出,因为突然a包含的元素数量减少了一个。因此索引也被抛弃了。
如果我只是执行这个:

a = [1,2,3,4]
a.each do
  |thing| 
  puts thing
  a.delete(thing)
end

我将得到输出 [1,3]。这是因为发生了以下情况:
在我从索引 0 处的列表中删除 1 之前,2 位于索引 1 处。删除 1 后,2 位于索引 0 而不是 1,所以不是 2 是下一个元素那是迭代的,但是 3!

顺便说一句,您可以像我一样定义一个局部块变量thing来访问您迭代的每个元素。

解决方案
为了获得您想要的,您需要创建一个副本并进行处理。

 a = [1,2,3,4]
 b = a.clone
 a.each do
   |thing|
   puts thing
   b.delete(thing)
 end

现在 a 在您迭代它时保持不变,而您改为更改 b。所以在这个循环结束时a = [1,2,3,4]b =[].
在你说a = b你会得到想要的结果。

当然,您可以调整它以从后面弹出元素。只需确保在副本上工作,这样您就不会在迭代时更改元素。

于 2013-05-10T09:31:48.857 回答
2

其他一些答案说明了为什么您的代码不起作用。

另一种方法是这样的(前提是您没有nilor falsein a):

a = [1,2,3,4]
while e = a.pop
  puts "Removing #{e}"
end
于 2013-05-10T09:25:36.920 回答
1

查看输出,这清楚地说明了为什么在您看来每个都没有使用所有数组元素运行。正如你pop(ing)一样Array#pop,最后的元素被删除。当每个传递2到块时,原始数组a为空,因此each停止迭代。:

a = [1,2,3,4]  
a.each do |i| 
  puts i
  puts "Removing #{a.last}"  
  p a.pop  
  p "========"
end

输出:

1
Removing 4
4
"========"
2
Removing 3
3
"========"

因此,您可以使用以下内容:

a = [1,2,3,4]  
(0...a.size).each do |i|
p a.pop
end

输出:

4
3
2
1
于 2013-05-10T08:43:36.987 回答
0
a = [1,2,3,4]  
a.length.times do  
  puts "Removing #{a.last}"  
  a.pop  
end
于 2013-05-10T08:50:42.463 回答
0

试试这个:

a.count.times do a.pop and puts "Removing #{a.last + 1 rescue 1}" end

应该在 do 循环中做同样的事情

于 2013-05-10T09:26:55.177 回答