要素がまだない場合は、要素を配列に追加します


92

Rubyクラスがあります

class MyClass
  attr_writer :item1, :item2
end

my_array = get_array_of_my_class() #my_array is an array of MyClass
unique_array_of_item1 = []

にプッシュMyClass#item1したいのですがunique_array_of_item1、それがまだunique_array_of_item1含まれていない場合のみですitem1。私が知っている簡単な解決策があります:単に反復してmy_arrayunique_array_of_item1すでに現在のものが含まれているかどうかを確認しitem1ます。

より効率的な解決策はありますか?

回答:


82

Arrayの代わりにSetを使用できます。


ドキュメントがセットは順序ではないと言っているのは事実ですが、実際には(Ruby 1.9では)順序付けされています。コードを見ると、順序を取得するために使用する主なメソッド(Set#eachおよびなどSet#to_a)がに委譲されてい@hashます。また、Ruby 1.9の時点でハッシュが注文されました。「ハッシュは、対応するキーが挿入された順序で値を列挙します。」ruby-doc.org/core-1.9.1/Hash.html
phylae

決して新しいものはセットとしてありませんでした。彼らは素晴らしいです、どうもありがとう
ブラッド

123

@Coorasseには良い答えがありますが、次のとおりです。

my_array | [item]

そして、適切に更新するにmy_arrayは:

my_array |= [item]

63
またはmy_array |= [item]、更新my_arrayされます
アンドロフ2014年

2
たぶんここで何かが足りないのですが、| =演算子が機能しないようです。私は、Ruby 2.1.1実行しているよ
ベトナム

@Viet |=は、2.1.1のテストで問題なく機能します。テストケースを説明するか、新しい質問を開いてください。
2014年

もう一度テストすると、今は機能します。私のコメントは何ヶ月も前に行われたので、私が以前何をしていたのかわからない。
ベトナム

1
これの複雑さは何ですか?
のび太

40

my_array手作業で繰り返す必要はありません。

my_array.push(item1) unless my_array.include?(item1)

編集:

Tombartが彼のコメントで指摘しているように、使用Array#include?はあまり効率的ではありません。小さな配列ではパフォーマンスへの影響は無視できると思いますが、大きな配列ではそれに合わせた方がいいかもしれませんSet


6
あなたは間違いなくそれをしたくない!array.include?(item)複雑さがありますO(n)-配列全体を反復するようなものです このベンチマークをご覧ください
トゥームバルト

32

item1を配列に変換して結合することができます:

my_array | [item1]

1
これはすべきではあり|ません||(Jasonの回答を参照)
Seth

1
私のせい。ごめんなさい。回答を編集
coorasse 14年

3

Setクラスと| メソッド(「Set Union」とも呼ばれます)は一意の要素の配列を生成します。これは重複が必要ない場合に最適ですが、元の配列に非一意の要素がある場合は不愉快な驚きになります。

元の配列に失わないようにする重複した要素が少なくとも1つある場合、初期の戻り値で配列を反復することは最悪の場合のO(n)であり、これは物事のグランドスキームではそれほど悪くありません。

class Array
  def add_if_unique element
    return self if include? element
    push element
  end
end

0

それが完璧な解決策であるかどうかはわかりませんが、私にとってはうまくいきました:

    host_group = Array.new if not host_group.kind_of?(Array)
    host_group.push(host)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.