为什么Array.each里面的Array.delete不会删除所有项目?

时间:2013-01-18 20:54:44

标签: arrays ruby

我是Ruby的新手,我写了一个非常简单的应用程序来打印一周中的几天,然后在循环中删除一天:

def print_days(days)
    days.each do |day|
        print "The day of the week is: #{day}\n"
        days.delete(day)
        print "\n*****************************************************\n"
        print days
        print "\n*****************************************************\n"
    end
end

wd = %w[Monday Tuesday Wednesday Thursday Friday Saturday Sunday]

print print_days(wd

运行时会显示以下输出。任何人都可以解释为什么当我按顺序删除每个元素并且数组显示它们在那里时,周二,周四和周六被跳过了?您可以在设置中运行这个简单的代码:

The day of the week is: Monday

*****************************************************
["Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
*****************************************************
The day of the week is: Wednesday

*****************************************************
["Tuesday", "Thursday", "Friday", "Saturday", "Sunday"]
*****************************************************
The day of the week is: Friday

*****************************************************
["Tuesday", "Thursday", "Saturday", "Sunday"]
*****************************************************
The day of the week is: Sunday

*****************************************************
["Tuesday", "Thursday", "Saturday"]
*****************************************************
["Tuesday", "Thursday", "Saturday"]

4 个答案:

答案 0 :(得分:4)

在迭代数组时,您正在从数组中删除元素,使迭代器无效。

你可以尝试

   until (days.empty?) 
       day = days.shift
       print "The day of the week is: #{day}\n"
   end

   days.each{|day| print "The day of the week is: #{day}\n"}
   days.clear

答案 1 :(得分:3)

您正在迭代所有元素期间修改数组。在内部,每个方法都保持它产生的最后一个项目的索引。这基本上使迭代器无效。其他语言会为您抛出异常。

Ruby没有。

所以在第一次通过它时会产生索引为0的元素

然后删除索引0处的元素

然后下一次通过它会产生索引为1的元素,它基本上会跳过星期二,因为它现在在索引0处。

答案 2 :(得分:2)

你违反了基本规则,当你在迭代它时,不要改变你正在迭代的对象!

这里发生了什么:

  1. 迭代数组
  2. 从第一项开始
  3. 删除第一项
  4. 数组中的第二项现在是第一项。
  5. 抓住第二个项目,由于前一个第二个项目现在是第一个,它抓住了以前的第三个​​项目。
  6. 删除变异数组中的第二项(以前是第三项)
  7. 所以它会跳过删除所有其他项目。这些类型的奇怪错误是为什么当你迭代它时,更改你正在迭代的对象是非常不满意的。不要那样做。

    但考虑到你的例子是多么做作,很难提出一个更好的方法。根据您的实际目标,有更好的方法来实现这一目标。

答案 3 :(得分:0)

鉴于上述大多数答案都解释了为什么你所做的是失败,你可以使用

的变体来获得你想要的东西。
Array#drop_while
Array#delete_if
Array#select!

Array#keep_if

e.g。

a=[1,2,3,4]
a.drop_while{|e| puts e; true}

给出

1
2
3
4
 => []