解决这个ruby迭代器难题的干净方法?

解决这个ruby迭代器难题的干净方法?,ruby,arrays,iterator,for-loop,enumerable,Ruby,Arrays,Iterator,For Loop,Enumerable,另一个数组迭代器k也会产生同样的效果 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] 具有相同的输出 发生这种情况的原因非常清楚……Ruby实际上并不遍历存储在数组中的对象,而是将其转换为一个漂亮的

另一个数组迭代器k也会产生同样的效果

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]
具有相同的输出

发生这种情况的原因非常清楚……Ruby实际上并不遍历存储在数组中的对象,而是将其转换为一个漂亮的数组索引迭代器,从索引0开始,每次增加索引,直到结束。但是当你删除一个项目时,它仍然会增加索引,所以它不会对同一个索引求值两次,我希望它这样做

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

有没有干净的方法可以做到这一点?是否已经有一个内置迭代器可以做到这一点?或者我必须弄脏它并执行数组索引迭代器,而不是在删除项时递增?(或遍历数组的克隆,并从原始数组中删除)


澄清

我不想简单地从数组中删除项目;如果这是清楚的,我很抱歉。我想做的是迭代每个元素,并“处理”它;此过程有时可能会删除它。更准确地说:

k = [1,2,3,4,5]
k.each do |n|
  puts n
  if n == 2
    k.delete(n)
  end
end
puts k.join(",")
class-Living\u东西
def初始化跟踪程序,id
@跟踪器
@id=id
@跟踪器[1,2,3,4]
对于n,在跟踪数组中
n、 过程
结束
#结果:仅处理foo、bar和oof
理想情况下,我希望处理跟踪数组中的所有项


当Living_Thing从跟踪_数组中移除时,必须调用Living_Thing#die;do_stuff_to_die会清理必须组合的东西。

好的,假设您想从阵列中消除所有2个:

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
但我怀疑您想要迭代,所以我会:

arr = [1,2,3,4,5]
arr.delete(2)
puts arr.join(", ")
# => "1, 3, 4, 5"
arr = [1,2,3,2,4,2,5,2]
arr.delete(2)
puts arr.join(", ")
# => "1, 3, 4, 5"
也许那太脏了?对nil的赋值使迭代器计数保持正确,
紧凑在事实发生后清除零。课程
map
使其略短且更干净:

arr = [1,2,3,4,5]
arr.each {|x| a[a.index(x)] = nil if x == 2}.compact!

在大多数语言中,在迭代集合时对其进行变异是错误的。在大多数语言中,解决方案是创建一个副本并对其进行修改,或者建立一个索引列表,在完成迭代时对这些索引执行操作,但是Ruby的迭代器提供的功能远不止这些。有几个解决方案是显而易见的。国际海事组织最惯用的说法是:

arr.map {|x| x if x != 2}.compact!
从您的示例更直接地翻译为:

puts k
puts k.reject {|n| n == 2}.join(',')

delete\u如果
基本上是
reject
的破坏性版本,它返回块未返回true的对象数组。)

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


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

nice,我喜欢delete\u if非常干净的解决方案使用delete\u if为每个项目运行完整的代码块非常优雅;我非常喜欢它=)我一定会把它放在我的武器库里;但是,对于我当前的问题,它不太有效=/或者使用
reject
相当于
删除(如果
)。谢谢;我没有想到在一行中使用k.dup和.each,而不是使用temp变量;这是我现在将要使用的解决方案…虽然,是的,它确实回避了实际的迭代删除问题。这是针对Rails应用程序还是仅仅针对Ruby?
k.delete_if do |n|
  puts n
  n == 2
end
puts k.join(',')
k = [1,2,3,4,5] 
k.dup.each do |n| 
  puts n 
  if n == 2
    k.delete(n) 
  end 
end 
puts k.join(",")