Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby 鲁比没有';t循环所有元素?_Ruby - Fatal编程技术网

Ruby 鲁比没有';t循环所有元素?

Ruby 鲁比没有';t循环所有元素?,ruby,Ruby,我正在尝试从数组中删除所有7s: 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] 这是怎么发生的?这是因为在每次迭代中,您都在更新/删除循环使用的相同数

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

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]  

这是怎么发生的?

这是因为在每次迭代中,您都在更新/删除循环使用的相同数组

为此,应使用以下方法:

您可以通过运行以下程序查看问题:

a = [1,2,3,4,5,6]
a.each_with_index do |item, index|
    puts "#{index} : #{item}"
    if item == 4
        a.delete_at(index)
    end
end
输出:

0 : 1
1 : 2
2 : 3
3 : 4  # made delete here
4 : 6  # See the problem !

希望能有所帮助:)

事实上,只有大约一半(5/9)的项目消失了,这是一个致命的漏洞,问题是在迭代集合时删除

迭代将处理索引1、2、3、4等等。如果在处理索引2时将其删除,则会将以后的所有索引下移1

因此,当您在下一次迭代中继续移动到索引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/9
7
s被删除,四对中每对一个,最后一对是独立的

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

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

a.delete_if {|val| val > 7}

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

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

a.to_enum.with_index.reverse_each do |item, index|
该行将以这样一种方式处理数组,即删除不会影响将来的操作。请注意,如果正在处理的数据结构不是简单的索引数组,则在迭代时删除仍然可能是一个问题


我仍然保证
delete
delete\u if
是正确的方法,因为它们已经被烘焙到Ruby中,因此不太可能有bug。

一般来说,从你正在迭代的数组中删除,用任何语言,都会变得很奇怪。要了解原因,请查看的代码


请注意,上两次迭代已经离开了数组,因为数组现在比以前小了两个元素。

因为您在删除时looping@dnit13所以删除数组中所有7个的正确方法是?
a.delete(7)
当然是正确的方法,但是如果你想在迭代时删除,你必须这样做:
b=a.dup;(a.size-1)。向下至(0)。如果b[j]==7,则在(j)处删除每个{j}b;b#=>[1,2,3,4,5,9,10,11,12,13]
。感谢您的解释,非常有用。如果我只想循环和删除怎么办?我写这个小程序是因为我试图从一个大的JSON数组中删除元素,但事情并没有像我所说的那样进行,所以我写这个程序是为了理解循环和删除是如何工作的Ruby@NamNamNam前面提到的
数组#delete_如果
在引擎盖下循环并删除。感谢您的长回答和Ruby源代码!令人惊叹的!
a.delete_if {|val| val > 7}
a.to_enum.with_index.reverse_each do |item, index|
VALUE rb_ary_each_index(VALUE ary)
{
    long i;
    RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);

    for (i=0; i<RARRAY_LEN(ary); i++) {
        rb_yield(LONG2NUM(i));
    }
    return ary;
}
i = 0
a = [1,2,2,2,3,4,5]
     ^
-------------------
i = 1
a = [1,2,2,2,3,4,5]
       ^
a.delete_at(i)
a = [1,2,2,3,4,5]
-------------------
i = 2
a = [1,2,2,3,4,5]
         ^
a.delete_at(i)
a = [1,2,3,4,5]
-------------------
i = 3
a = [1,2,3,4,5]
           ^
-------------------
i = 4
a = [1,2,3,4,5]
             ^
-------------------
i = 5
a = [1,2,3,4,5]
-------------------
i = 6
a = [1,2,3,4,5]