web-dev-qa-db-ja.com

Javaで配列内の重複を削除する最良の方法は何ですか?

重複を削除/フィルタリングする必要があるオブジェクトの配列があります。 Object要素のequals&hachCodeをオーバーライドして、それらをSetに貼り付けるつもりでした...しかし、少なくともstackoverflowをポーリングして、別の方法、おそらく他のAPIの巧妙な方法があるかどうかを確認する必要があると考えました。

15
Liggy

hashCode()equals()をオーバーライドし、Setを実装するものを使用するというあなたのアプローチに同意します。

そうすることで、他の開発者にとって、重複しない特性が必要であることを完全に明確にすることもできます。

もう1つの理由-あなたは今あなたのニーズに最も合う実装を選ぶことができます:

将来、実装を変更するためにコードを変更する必要はありません。

21
brabster

私はこれをウェブで見つけました

ArrayList内の重複を削除できる2つのメソッドを次に示します。 removeDuplicateは順序を維持しませんが、removeDuplicateWithOrderはパフォーマンスのオーバーヘッドを伴う順序を維持します。

  1. RemoveDuplicateメソッド:

    /** List order not maintained **/
    public static void removeDuplicate(ArrayList arlList)
    {
     HashSet h = new HashSet(arlList);
     arlList.clear();
     arlList.addAll(h);
    }
    
  2. RemoveDuplicateWithOrderメソッド:

    /** List order maintained **/
    public static void removeDuplicateWithOrder(ArrayList arlList)
    {
       Set set = new HashSet();
       List newList = new ArrayList();
       for (Iterator iter = arlList.iterator(); iter.hasNext();) {
          Object element = iter.next();
          if (set.add(element))
             newList.add(element);
       }
       arlList.clear();
       arlList.addAll(newList);
    }
    
9
Markus Lausberg

equalshashCodeをオーバーライドしてセットを作成することも、私の最初の考えでした。とにかく、継承階層にこれらのメソッドのオーバーライドバージョンを含めることをお勧めします。

I thinkLinkedHashSetを使用すると、一意の要素の順序も保持されると思います...

3
Dan Vinton

List distinctListを使用して、最初にiteratorが要素に遭遇したときに要素を記録し、リストがすべての重複を削除したときに、distinctListを返します


 private List removeDups(List list) {
        Set tempSet = new HashSet();
        List distinctList = new ArrayList();
        for(Iterator  it = list.iterator(); it.hasNext();) {
            Object next = it.next();
            if(tempSet.add(next)) {
                distinctList.add(next);
            } 
        }
        return distinctList;
   } 
2
didxga

基本的に、ランダムアクセス用のLinkedHashSet<T>インターフェイスをサポートするList<T>実装が必要です。したがって、これはあなたが必要とするものです:

public class LinkedHashSetList<T> extends LinkedHashSet<T> implements List<T> {

// Implementations for List<T> methods here...

}

List<T>メソッドの実装は、基礎となるLinkedHashSet<T>にアクセスして操作します。秘訣は、List<T> addメソッドを介して重複を追加しようとしたときにこのクラスが正しく動作するようにすることです(例外をスローするか、別のインデックスでアイテムを再追加するのがオプションです。どちらかを選択するか、クラスのユーザーが構成可能にする)。

2
Ryan Delucchi

コメントでジェイソンの指摘を繰り返したいと思います。

なぜその時点に身を置くのですか?

重複をまったく保持してはならないデータ構造に配列を使用するのはなぜですか?

要素を保持するには、常にSetまたはSortedSet(要素にも自然な順序がある場合)を使用します。挿入順序を維持する必要がある場合は、指摘されているようにLinkedHashSetを使用できます。

多くの場合、データ構造を後処理する必要があるということは、最初に別のデータ構造を選択する必要があるというヒントです。

1
Joachim Sauer

もちろん、元の投稿では、「そもそも、その配列(重複したエントリが含まれている可能性がある)をどのようにして取得したのですか?」という疑問が生じます。

他の目的で(重複した)配列が必要ですか、それとも最初からセットを使用するだけですか?

または、各値の出現回数を知る必要がある場合は、Map<CustomObject, Integer>を使用してカウントを追跡できます。また、 Googleコレクション マルチマップクラスの定義が役立つ場合があります。

1
joel.neely

Setは間違いなく最善の策です。配列から(新しいものを作成せずに)削除する唯一の方法は、それらをnullにすることです。そうすると、後で多くのnullチェックが発生します。

0
Michael Myers

一般的なプログラミング標準から言えば、コレクションを常に二重に列挙してから、ソースとターゲットを比較することができます。

そして、内部列挙が常にソースの後に1つのエントリを開始する場合、それはかなり効率的です(続く擬似コード)

foreach ( array as source )
{
    // keep track where we are in the array
    place++;
    // loop the array starting at the entry AFTER the current one we are comparing to
    for ( i=place+1; i < max(array); i++ )
    {
        if ( source === array[place] )
        {
            destroy(array[i]);
        }
    }
}

間違いなく休憩を追加することができます。破棄後のステートメントですが、最初の重複のみが検出されますが、それがすべてである場合は、小さな最適化になります。

0
TravisO