为什么我的过滤器方法没有删除一些应该删除的元素?

Cha*_*ham 1 ruby array-unique proc

我正在尝试创建一个名为 filer_out 的方法!它接受一个数组和一个 proc,并返回相同的数组,但每个元素在通过 proc 时都返回 true,但需要注意的是我们不能使用 Array#reject!

我是这样写的:

def filter_out!(array, &prc)
    array.each { |el| array.delete(el) if prc.call(el)}
end

arr_2 = [1, 7, 3, 5 ]
filter_out!(arr_2) { |x| x.odd? }
p arr_2
Run Code Online (Sandbox Code Playgroud)

但是当我运行代码时,打印出来的是:

[7, 5]
Run Code Online (Sandbox Code Playgroud)

即使答案应该是:

[]
Run Code Online (Sandbox Code Playgroud)

在查看解决方案后,我看到首先使用了 Array#uniq:

def filter_out!(array, &prc)
    array.uniq.each { |el| array.delete(el) if prc.call(el) }
end

arr_2 = [1, 7, 3, 5 ]
filter_out!(arr_2) { |x| x.odd? }
p arr_2
Run Code Online (Sandbox Code Playgroud)

并显示了正确的输出:

[]
Run Code Online (Sandbox Code Playgroud)

所以我想我的问题是,为什么必须使用 Array#uniq 才能获得正确的解决方案?感谢您的帮助!

Nin*_* Le 5

这里的问题是delete修改原始数组的方法。如果你提供一些信息,这里的交易:

def filter_out!(array, &prc)
  array.each.with_index do |el, i|
    p "Current index #{i}"
    p "Current array #{array}"
    p "Current element #{el}"
    array.delete(el) if prc.call(el)
  end
end

arr_2 = [1, 7, 3, 5 ]
filter_out!(arr_2) { |x| x.odd? }
# Output:
#"Current index 0"
# "Current array [1, 7, 3, 5]"
# "Current element 1"
# "Current index 1"
# "Current array [7, 3, 5]"
# "Current element 3"
Run Code Online (Sandbox Code Playgroud)

解释:

  • 第一次,元素是1,删除后数组是[7, 3, 5]
  • 第二次,迭代中的索引为1,获取当前数组中具有该索引的当前元素,本例中为3不是7,删除,删除数组后为[3, 5]
  • 两次后它停止迭代,因为当前索引超出当前数组的范围

通过使用uniq您可以获得正确的结果,因为array.uniq它在修改原始数组时创建原始数组的副本,它仍然按预期迭代。