2

我是 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

4 回答 4

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
于 2013-01-18T20:58:45.550 回答
3

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

红宝石没有。

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

然后删除索引 0 处的元素

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

于 2013-01-18T21:00:15.723 回答
2

你打破了基本规则,不要在你迭代的时候改变你正在迭代的对象!

这里发生了什么:

  1. 遍历数组
  2. 从第一项开始
  3. 删除第一项
  4. 数组中的第二项现在是第一项。
  5. 抓住第二个项目,因为之前的第二个项目现在是第一个,所以它抓住了以前的第三个项目。
  6. 删除变异数组中的第二项(以前是第三项)

所以它有点跳过删除所有其他项目。这些类型的奇怪错误是为什么在迭代时更改正在迭代的对象非常不受欢迎的原因。不要那样做。

但是考虑到您的示例是多么人为,很难提出更好的方法。根据您的实际目标,有更好的方法来做到这一点。

于 2013-01-18T21:02:25.767 回答
0

鉴于上述大多数答案都解释了为什么您正在做的事情失败了,您可以使用

Array#drop_while
Array#delete_if
Array#select!

或者

Array#keep_if

例如

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

1
2
3
4
 => []
于 2013-01-18T22:53:27.037 回答