重複を削除/フィルタリングする必要があるオブジェクトの配列があります。Object 要素の equals と hachCode をオーバーライドして、それらを Set に貼り付けるつもりでしたが、少なくともスタックオーバーフローをポーリングして、別の方法、おそらく他の API の巧妙な方法があるかどうかを確認する必要があると考えました。
9 に答える
実装するものをオーバーライドhashCode()
して使用するというあなたのアプローチに同意します。equals()
Set
そうすることで、重複しない特性が必要であることを他の開発者に完全に明確にします。
もう 1 つの理由は、現在のニーズに最適な実装を選択できることです。
将来的に実装を変更するためにコードを変更する必要はありません。
私はウェブでこれを見つけました
ArrayList 内の重複を削除できる 2 つのメソッドを次に示します。removeDuplicate は順序を維持しませんが、removeDuplicateWithOrder は順序を維持しますが、パフォーマンスのオーバーヘッドはいくらかあります。
removeDuplicate メソッド:
/** List order not maintained **/ public static void removeDuplicate(ArrayList arlList) { HashSet h = new HashSet(arlList); arlList.clear(); arlList.addAll(h); }
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); }
セットをオーバーライドequals
しhashCode
て作成することも最初に考えました。とにかく、継承階層にこれらのメソッドのオーバーライドされたバージョンをいくつか用意することをお勧めします。
a を使用すると、一意の要素の順序も保持されると思いますLinkedHashSet
...
リスト 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;
}
基本的に、ランダム アクセス用LinkedHashSet<T>
のインターフェイスをサポートする実装が必要です。List<T>
したがって、これはあなたが必要とするものです:
public class LinkedHashSetList<T> extends LinkedHashSet<T> implements List<T> {
// Implementations for List<T> methods here
...
}
メソッドの実装はList<T>
、基になる にアクセスして操作しLinkedHashSet<T>
ます。秘訣は、 add メソッドを介して重複を追加しようとしたときに、このクラスが正しく動作するようにすることList<T>
です (例外をスローするか、別のインデックスでアイテムを再度追加することがオプションになります。いずれかを選択するか、ユーザーが構成可能にすることができますクラス)。
もちろん、元の投稿では、「そもそもその配列 (重複したエントリが含まれている可能性がある) をどのように取得したのですか?」という疑問が生じます。
他の目的で配列 (複製を含む) が必要ですか、それとも最初から Set を使用できますか?
または、各値の出現回数を知る必要がある場合は、a を使用しMap<CustomObject, Integer>
てカウントを追跡できます。また、Multimap クラスのGoogle Collections定義が役立つ場合があります。
コメントでジェイソンが指摘した点を繰り返したいと思います。
なぜその時点に身を置くのですか?
重複をまったく保持してはならないデータ構造に配列を使用するのはなぜですか?
要素を保持するには、常にaSet
または a (要素に自然な順序もある場合) を使用します。SortedSet
挿入順序を維持する必要がある場合は、LinkedHashSet
指摘されているとおりに使用できます。
一部のデータ構造を後処理する必要があることは、多くの場合、最初から別のものを選択する必要があるというヒントです。
ASet
は間違いなくあなたの最善の策です。(新しい配列を作成せずに) 配列から要素を削除する唯一の方法は、それらを null にすることです。その後、後で多くの null チェックが必要になります。
一般的なプログラミング標準から言えば、いつでもコレクションを二重に列挙してから、ソースとターゲットを比較できます。
また、内部列挙が常にソースの 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]);
}
}
}
間違いなく休憩を追加できます。destroy の後のステートメントですが、最初の重複を発見するだけです。