清洁解决这个红宝石迭代器的诡计?

Jus*_* L. 10 ruby arrays iterator for-loop enumerable

k = [1,2,3,4,5]
for n in k
  puts n
  if n == 2
    k.delete(n)
  end
end
puts k.join(",")

# Result:
# 1
# 2
# 4
# 5
# [1,3,4,5]

# Desired:
# 1
# 2
# 3
# 4
# 5
# [1,3,4,5]
Run Code Online (Sandbox Code Playgroud)

其他数组迭代器,k.each也会发生同样的效果:

k = [1,2,3,4,5]
k.each do |n|
  puts n
  if n == 2
    k.delete(n)
  end
end
puts k.join(",")
Run Code Online (Sandbox Code Playgroud)

具有相同的输出.

这种情况发生的原因非常清楚...... Ruby实际上并没有迭代存储在数组中的对象,而只是将它变成一个漂亮的数组索引迭代器,从索引0开始,每次都增加索引直到它结束.但是当你删除一个项目时,它仍然会增加索引,所以它不会两次评估相同的索引,这是我想要的.

可能不是正在发生的事情,但这是我能想到的最好的.

有干净的方法吗?是否已有可以执行此操作的内置迭代器?或者我是否需要弄脏并执行数组索引迭代器,并且在删除项目时不会增加?(或遍历数组的克隆,并从原始数组中删除)


澄清

我不只是想从数组中删除项目; 对不起,如果那是清楚的.我想要做的是遍历每个元素,并"处理"它; 此过程有时可能会删除它.为了更准确:

class Living_Thing

  def initialize tracker,id
    @tracker = tracker
    @id = id

    @tracker << self
  end

  def process
    do_stuff
    puts @id
    if @id == 2
      die
    end
  end

  def die
    do_stuff_to_die
    @tracker.delete(self)
  end

  def inspect
    @id
  end
end

tracking_array = Array.new()

foo = Living_Thing.new(tracking_array,1)
bar = Living_Thing.new(tracking_array,2)
rab = Living_Thing.new(tracking_array,3)
oof = Living_Thing.new(tracking_array,4)

puts tracking_array.join(",")              # => [1, 2, 3, 4]

for n in tracking_array
  n.process
end

# result: only foo, bar, and oof are processed
Run Code Online (Sandbox Code Playgroud)

理想情况下,我希望处理tracking_array中的所有项目.

当从tracking_array中删除Living_Thing时,必须调用Living_Thing #die ; do_stuff_to_die清理必须被绑定的东西.

Chu*_*uck 15

在迭代它时,在大多数语言中修改集合是一个错误.在大多数语言中,解决方案是创建一个副本并进行变异或构建索引列表,并在完成迭代时对这些索引执行操作,但Ruby的迭代器会为您提供更多.一些解决方案显而易见.最惯用的IMO:

puts k
puts k.reject {|n| n == 2}.join(',')
Run Code Online (Sandbox Code Playgroud)

更直接地从您的示例翻译:

k.delete_if do |n|
  puts n
  n == 2
end
puts k.join(',')
Run Code Online (Sandbox Code Playgroud)

(delete_if基本上是破坏性版本reject,它返回块未返回true的对象数组.)


pot*_*ngs 4

这可能更适合处理(参考更新的澄清)

k = [1,2,3,4,5] 
k.dup.each do |n| 
  puts n 
  if n == 2
    k.delete(n) 
  end 
end 
puts k.join(",")
Run Code Online (Sandbox Code Playgroud)

它回避了您所遇到的问题(关于通过对象迭代与通过索引迭代)