我正在尝试以下代码:
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)。
我怀疑这是因为您在修改列表时迭代列表的元素。
尝试以下操作:
a = [1,2,3,4]
until a.empty? do
puts "Removing #{a.last}"
a.pop
end
问题
当您迭代时,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
你会得到想要的结果。
当然,您可以调整它以从后面弹出元素。只需确保在副本上工作,这样您就不会在迭代时更改元素。
其他一些答案说明了为什么您的代码不起作用。
另一种方法是这样的(前提是您没有nil
or false
in a
):
a = [1,2,3,4]
while e = a.pop
puts "Removing #{e}"
end
查看输出,这清楚地说明了为什么在您看来每个都没有使用所有数组元素运行。正如你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
a = [1,2,3,4]
a.length.times do
puts "Removing #{a.last}"
a.pop
end
试试这个:
a.count.times do a.pop and puts "Removing #{a.last + 1 rescue 1}" end
应该在 do 循环中做同样的事情