リストから重複を削除したいのですが、私がやっていることは機能していません:
List<Customer> listCustomer = new ArrayList<Customer>();
for (Customer customer: tmpListCustomer)
{
if (!listCustomer.contains(customer))
{
listCustomer.add(customer);
}
}
そのコードが機能しない場合は、Customer
クラスにequals(Object)
を適切に実装していない可能性があります。
おそらく、顧客を一意に識別するキーがあります(customerId
と呼びます)。例えば.
_class Customer {
private String customerId;
...
_
equals(Object)
の適切な定義は次のようになります。
_ public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof Customer)) {
return false;
}
Customer other = (Customer) obj;
return this.customerId.equals(other.customerId);
}
_
完全を期すために、shouldもhashCode
を実装して、等しい2つのCustomer
オブジェクトが同じハッシュ値を返すようにします。上記のhashCode
の定義に一致するequals
は次のようになります。
_ public int hashCode() {
return customerId.hashCode();
}
_
リストが大きい場合、これは重複を削除する効率的な方法ではないことにも注意してください。 (N人の顧客を含むリストの場合、最悪の場合にN*(N-1)/2
比較を実行する必要があります。つまり、重複がない場合です。)より効率的なソリューションの場合は、HashSet
重複チェックを行います。
現在の順序を維持したい場合Set
を望まない場合、おそらく最も簡単です:
List<Customer> depdupeCustomers =
new ArrayList<>(new LinkedHashSet<>(customers));
元のリストを変更する場合:
Set<Customer> depdupeCustomers = new LinkedHashSet<>(customers);
customers.clear();
customers.addAll(dedupeCustomers);
Java 8アップデート
次のように配列のストリームを使用できます。
Arrays.stream(yourArray).distinct()
.collect(Collectors.toList());
お客様はequals()
契約を実装していますか?
equals()
およびhashCode()
を実装していない場合、listCustomer.contains(customer)
は、まったく同じインスタンスはすでにリストに存在します(インスタンスによって、まったく同じオブジェクトを意味します-メモリアドレスなど)。探しているのが同じかどうかをテストする場合Customer(おそらく同じ顧客名または顧客番号を持っている場合は同じ顧客です)が既にリストにある場合は、equals()
をオーバーライドして、関連するフィールド(顧客名など)が一致するかどうかを確認する必要があります。
注:hashCode()
をオーバーライドする場合は、equals()
をオーバーライドすることを忘れないでください!そうしないと、HashMapおよびその他のデータ構造に問題が生じる可能性があります。これがなぜなのか、どのような落とし穴を避けるのが良いかについては、Josh Blochの Effective Javaequals()
およびhashCode()
(リンクhashCode()
を実装するときにequals()
を実装しなければならない理由に関する情報のみが含まれていますが、equals()
をオーバーライドする方法についても十分な説明があります。
ところで、セットには順序の制限がありますか?存在しない場合、この問題を解決する少し簡単な方法は、Set<Customer>
そのようです:
Set<Customer> noDups = new HashSet<Customer>();
noDups.addAll(tmpListCustomer);
return new ArrayList<Customer>(noDups);
セットでは重複が許可されないため、重複がうまく削除されます。ただし、tmpListCustomer
には明示的な順序がないため、HashSet
に適用された順序は失われます(TreeSet
を使用して回避できますが、正確には関係ありません)あなたの質問に)。これにより、コードを少し簡素化できます。
すべての要素を Set
に追加するだけです。要素の繰り返しは許可されません。後でリストが必要な場合は、後で新しいArrayList(theSet)
コンストラクターを使用します(theSet
は結果セットです)。
Customer.equals()
が適切に(またはまったく)実装されていない可能性があります。
List.contains()
は、equals()
を使用して、その要素のいずれかがパラメーターとして渡されたオブジェクトと同一であるかどうかを検証します。ただし、equals
のデフォルトの実装では、値のアイデンティティではなく物理的なアイデンティティをテストします。したがって、Customer
で上書きしていない場合、同じ状態の2つの異なるCustomerオブジェクトに対してfalseを返します。
equals
の実装方法 (およびそのペアである hashCode
の基本的な詳細は次のとおりです-実際には常に実装する必要がありますどちらかを実装する必要がある場合は両方)。 Customerクラスを表示していないため、より具体的なアドバイスを提供することは困難です。
他の人が指摘したように、手作業で作業するよりもSetを使用した方が良いですが、その場合でも、これらのメソッドを実装する必要があります。
「contains」メソッドは、Customer.equals(Object o)からtrueを返すエントリがリストに含まれているかどうかを検索しました。 Customerまたはその親のいずれかでequals(Object)をオーバーライドしていない場合、同じオブジェクトの既存のオカレンスのみを検索します。これはあなたが望んでいたものかもしれません。その場合、コードは動作するはずです。ただし、同じ顧客を表す2つのオブジェクトがないことを探している場合は、equals(Object)をオーバーライドしてtrueを返す必要があります。
また、Listの代わりにSetの実装の1つを使用すると、重複した削除が自動的に、より高速になります(非常に小さなリスト以外の場合)。同等のコードを提供する必要があります。
Equals()をオーバーライドする場合は、hashCode()もオーバーライドする必要があります。
private void removeTheDuplicates(List<Customer>myList) {
for(ListIterator<Customer>iterator = myList.listIterator(); iterator.hasNext();) {
Customer customer = iterator.next();
if(Collections.frequency(myList, customer) > 1) {
iterator.remove();
}
}
System.out.println(myList.toString());
}
上記の答えはほぼすべて正しいですが、パフォーマンスを上げるためではなく、関連リストの作成中にマップまたはセットを使用することをお勧めします。リストをセットまたはマップに変換してからリストに再変換するのは簡単な作業だからです。
サンプルコード:
Set<String> stringsSet = new LinkedHashSet<String>();//A Linked hash set
//prevents the adding order of the elements
for (String string: stringsList) {
stringsSet.add(string);
}
return new ArrayList<String>(stringsSet);
2つの提案:
ArrayListの代わりにHashSetを使用します。これにより、長いリストがある場合は、contains()チェックが大幅に高速化されます。
Customer.equals()およびCustomer.hashCode()が適切に実装されていることを確認します。つまり、これらは顧客オブジェクトの基になるフィールドの結合値に基づいている必要があります。
私見の最近のやり方:
コレクション "dups"があり、同じ要素を含むがすべての重複を排除した別のコレクションを作成するとします。次のワンライナーがトリックを行います。
Collection<collectionType> noDups = new HashSet<collectionType>(dups);
定義上、重複を含むことができないSetを作成することで機能します。
Oracle文書に基づいています
最もクリーンな方法は次のとおりです。
List<XXX> lstConsultada = dao.findByPropertyList(YYY);
List<XXX> lstFinal = new ArrayList<XXX>(new LinkedHashSet<GrupoOrigen>(XXX));
各エンティティのIdのプロパティでhascode
およびequals
をオーバーライドします
他の人が述べたように、おそらくequals()を正しく実装していないでしょう。
ただし、ランタイムは2乗した要素の数になる可能性があるため、このコードは非常に非効率的であると見なされることにも注意してください。
代わりにリストではなくセット構造を使用するか、最初にセットを構築してからリストに変換することを検討してください。
Javaの正しい答えは、 Set を使用することです。すでに_List<Customer>
_があり、それを複製したい場合
_Set<Customer> s = new HashSet<Customer>(listCustomer);
_
それ以外の場合は、Set
実装HashSet
、TreeSet
を直接使用し、List
構築フェーズをスキップします。
Set
に置かれているドメインクラスで hashCode()
およびequals()
もオーバーライドする必要があります。あなたが実際にあなたが得るものが欲しい。 equals()
は、オブジェクトの一意のIDを比較するだけの単純なものから、すべてのフィールドを比較するのと同じくらい複雑にすることができます。 hashCode()
は、一意のid 'String
表現のhashCode()
またはhashCode()
を返すのと同じくらい簡単です。
Java 8ストリームAPIを使用します。
List<String> list = new ArrayList<>();
list.add("one");
list.add("one");
list.add("two");
System.out.println(list);
Collection<String> c = list.stream().collect(Collectors.toSet());
System.out.println(c);
出力:
値の前:[1、1、2]
値の後:[1、2]