質問

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]

この同じ効果は、他のアレイイテレータで発生し、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(",")

は、同じ出力を備えています。

これが起こっている理由はかなり明確である... 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

理想的には、私はtracking_array内のすべての項目が処理されるようにしたいと思います。

Living_Thingがが呼び出されなければなりません#ダイをLiving_Thing、tracking_arrayから削除されます。

; do_stuff_to_dieアップclanedする必要が物事をクリーンアップします。

役に立ちましたか?

解決

これはより多くの処理に適しされる可能性があります(参考文献更新明確化)

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

その辺は(インデックスによる反復対オブジェクトを通じて反復程度)

けれども、あなたが持っていた疑問ステップ

他のヒント

それはあなたがそれを反復している間、コレクションを変異させるほとんどの言語でのエラーです。ほとんどの言語では、溶液は、というコピーとのmutateを作成したり、インデックスのリストを構築し、あなたが完了反復処理をしているとき、それらのインデックスに対して操作を実行することですが、Rubyのイテレータは、もう少しそれよりもあなたを与えます。ソリューションのカップルは明白です。最も慣用IMOます:

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

より直接あなたの例から翻訳ます:

k.delete_if do |n|
  puts n
  n == 2
end
puts k.join(',')

delete_ifがブロックのためにtrueを返していないことオブジェクトの配列を返す、基本的にrejectの破壊的なバージョンである。)

わかりましたので、あなたはあなたの配列からすべての2人の者を排除したいとしましょう。

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"

しかし、私は、私は希望ので、あなたが反復したい疑います:

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

多分それはあまりにも汚いのか? nilに割り当ては、イテレータカウント権利を保持し、かつcompact!は事実の後NILSを払拭します。コースmapは少し短く、それを維持し、クリーナーです。

arr.map {|x| x if x != 2}.compact!
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top