2011-11-01 9 views
6

delete_atは単一のインデックスしか取りません。組み込みのメソッドを使用してこれを達成するには良い方法はありますか? セットである必要はなく、インデックスの配列であってもかまいません。インデックスの集合に基づいて配列の内容を削除します

arr = ["a", "b", "c"] 
set = Set.new [1, 2] 
arr.delete_at set 
# => arr = ["a"] 
+0

は、必ずしもその場で修正しなければなりませんか? – tokland

+0

別の配列を使うのではなく、Set.newでSet型を使用して、一意性を保証していますか? – Mirv

答えて

12

ワンライナー:

arr.delete_if.with_index { |_, index| set.include? index } 
+0

'_'アンダースコアを探すのは難しいのでちょっとメモしてください - それはプレースホルダですこれは単にインデックスを無視する場合によく使用されます。 '_'は有効な変数ですが、コード行には何も進んでいません。 – Mirv

1

これを試してみてください:

arr.reject { |item| set.include? arr.index(item) } # => [a] 

それは私が考えて、少し醜いです;)たぶん誰かがよりよい解決策を提案しますか?

+0

私の問題のための簡単な解決策、他は失敗しました! – dariush

4

Arrayクラスを再オープンし、新しいメソッドを追加します。

class Array 

    def delete_at_multi(arr) 
    arr = arr.sort.reverse # delete highest indexes first. 
    arr.each do |i| 
     self.delete_at i 
    end 
    self 
    end 

end 

arr = ["a", "b", "c"] 
set = [1, 2] 

arr.delete_at_multi(set) 

arr # => ["a"] 

これはもちろん、クラスを再オープンしたくない場合は、スタンドアロンの方法として記述することができます。索引が逆順になっていることを確認することが重要です。そうしないと、後で削除されるはずの配列内の要素の位置が変更されます。

+0

+1ですが、* delete_at_indices *はより良い名前になります:delete_atの可読性は維持されますが、それでも複数のインデックスが必要であることは明らかです。あなたが「3時に削除」または「インデックス3,5、および7で削除する」と言っても、「マルチ3,5,7で削除」とは言っていません。 (そしてもちろん、 "索引"という言葉を使用することを嫌う人のために、別名* delete_at_indexes *;)があるかもしれません。 – iconoclast

0

機能アプローチ:

class Array 
    def except_values_at(*indexes) 
    ([-1] + indexes + [self.size]).sort.each_cons(2).flat_map do |idx1, idx2| 
     self[idx1+1...idx2] || [] 
    end 
    end 
end 

>> ["a", "b", "c", "d", "e"].except_values_at(1, 3) 
=> ["a", "c", "e"] 
関連する問題