Ruby 没有循环所有元素?

标签 ruby

我正在尝试从数组中删除所有 7:

a = [1,2,3,4,5,7,7,7,7,7,7,7,7,7,9,10,11,12,13]

我做到了:

a.each_with_index do |item, index|
  if item == 7
    a.delete_at(index)
  end
end
a # => [1, 2, 3, 4, 5, 7, 7, 7, 7, 9, 10, 11, 12, 13]  

这是怎么发生的?

最佳答案

事实上只有大约一半 (5/9) 的项目消失了,这表明问题是在遍历集合时删除。

迭代将处理索引 1、2、3、4 等。如果您在处理索引 2 时将其删除,则所有后面的索引都会向下移动一个。

因此,当您在下一次迭代中移动到索引 3 时,您将跳过原始索引 3,因为它已向下移动到索引 2。

换句话说,让我们从一个更简单的示例开始,其中包含要删除的两个连续项目:

index | 0 | 1 | 2 | 3 |
value | 1 | 7 | 7 | 9 |

您检查了第一个索引并且值为 1 所以您什么都不做。然后您检查第二个索引并且值为 7 因此您将其删除,给出:

index | 0 | 1 | 2 |
value | 1 | 7 | 9 |

然后您检查第三个​​ 索引并且值为9,因此您什么都不做。您也已到达终点,因此它停止了。

所以你可以看到你实际上跳过了你想删除的第二个项目,因为你在迭代时移动了一些东西。这不是 Ruby 特有的问题,很多语言都有同样的问题。

一般来说,每对完整的相邻项目只会删除该对中的第一个项目,而单独的项目(后面没有另一个具有相同值的项目)将被正常删除。这就是为什么只有 5/97 被删除,四对中的每一对和最后一个独立的一对。

删除单个给定值的所有项的正确方法(在 Ruby 中)是使用 array delete方法:

a.delete(7)

您还可以使用 conditional delete对于更复杂的条件,例如删除大于 7 的所有内容:

a.delete_if {|val| val > 7}

而且,如果您真的想自己做(作为一种教育练习),您只需要意识到问题是因为您以正向方式处理数组 - 当您这样做时,超出删除范围的更改可能会导致问题。

如果您找到某种方法以反向方式处理数组,则不会出现此问题。幸运的是,Ruby 有这样一个野兽:

a.to_enum.with_index.reverse_each do |item, index|

该行将以删除不会影响 future 操作的方式处理数组。请注意,如果您正在处理的数据结构不是简单的索引数组,那么在迭代时删除仍然是一个问题。

我仍然保证 deletedelete_if 是正确的方法,因为它们已经被嵌入到 Ruby 中,因此不太可能有错误。

关于Ruby 没有循环所有元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38428965/

相关文章:

ruby - 是否可以在 Solr/Lucene 中模拟余弦相似度?

ruby - ruby 中的组合逻辑问题

jquery - 让 Jekyll 从 {{ content }} 中删除 <p>

ruby - 将所有偶数索引整数乘以二

ruby-on-rails - rails : Having problems with follow and followed system

ruby - 获取 TypeError - 无法克隆符号 : error when using active_model_serializer

ruby - 在 Sinatra 中故意引发 500 个错误以测试它们的处理方式

ruby - 如何在 Ruby 中增加一个整数

ruby - 如何将数组中的多个对象铲到一个对象中?

ruby-on-rails - validates_inclusion_of、acts_as_tree 和 rspec 的问题