当サイトは、アフィリエイト広告を利用しています

【java8】streamAPIでオブジェクトListの重複チェックをする

作成日:2022月09月10日
更新日:2024年02月08日

java8のstreamAPIのfilter等を使ってオブジェクトのArrayListの
重複チェックをする方法をメモしておく。
※以外によく使うので

当ブログで紹介しているjava8のstreamAPIを使った
コレクションや配列の操作方法を
下記記事でメソッド別にまとめています!

重複を削除したい場合

streamAPIのdistinctでは重複チェックする値(キー)の
設定はできないのでオブジェクトの特定のプロパティで重複削除はできない
また、全プロパティで比較してもオブジェクトは参照アドレスで比較されるので
distinctでは重複を削除できない

HashSetとArrayListのremoveIfを使うパターン

HashSetの要素の重複を許可しない特性を使って
ArrayListのremoveIfで重複要素の削除を行うパターン

重複チェックキーが一つの場合

Setにキーをそのまま追加する

Main.java
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.*;
public class Main {
public static void main(String[] args) throws Exception {
//重複チェックキーとするidを重複させる
Person pob1 = new Person(1,"TANAKA","東京",11);
Person pob2 = new Person(2,"YAMADA","京都",12);
Person pob3 = new Person(3,"KOJIMA","東京",13);
Person pob4 = new Person(3,"MAJIMA","富山",13);
Person pob5 = new Person(4,"MAJIMA","富山",13);
//list作成
List<Person>pList = new ArrayList<>();
pList.add(pob1);
pList.add(pob2);
pList.add(pob3);
pList.add(pob4);
pList.add(pob5);
//セット作成
HashSet<Integer> seen = new HashSet<>();
//removeIfで重複削除
//idをキーにする
pList.removeIf(p->!seen.add(p.getId()));
System.out.println(pList);
}
}
// [{1 TANAKA 東京 11}, {2 YAMADA 京都 12}, {3 KOJIMA 東京 13}, {4 MAJIMA 富山 13}]
  • Setに先に入れた方が優先となるため、後のオブジェクトが削除されている

重複チェックキーが複数の場合

Setに追加するときに文字列結合して作ったキーを追加する

Main.java
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.*;
public class Main {
public static void main(String[] args) throws Exception {
//重複チェックキーとするnameとaddressを重複させる
Person pob1 = new Person(1,"TANAKA","東京",11);
Person pob2 = new Person(2,"YAMADA","京都",12);
Person pob3 = new Person(3,"KOJIMA","東京",13);
Person pob4 = new Person(3,"MAJIMA","富山",13);
Person pob5 = new Person(4,"MAJIMA","富山",13);
//list作成
List<Person>pList = new ArrayList<>();
pList.add(pob1);
pList.add(pob2);
pList.add(pob3);
pList.add(pob4);
pList.add(pob5);
//セット作成
HashSet<String> seen = new HashSet<>();
//removeIfで重複削除
//名前と住所の複合キーを作る
pList.removeIf(p->!seen.add(p.getName() + p.getAddress()));
System.out.println(pList);
}
}
// [{1 TANAKA 東京 11}, {2 YAMADA 京都 12}, {3 KOJIMA 東京 13}, {3 MAJIMA 富山 13}]
  • Setに先に入れた方が優先となるため、後のオブジェクトが削除されている
  • キーが増える場合は文字列結合させるさらに増やせば対応できる。

動作確認

重複キーが一つの場合の動作を確認する

【java8】javaでのListの重複削除

参考

Collectorsクラスのメソッドを使う場合

CollectorsクラスのcollectingAndThenとtoCollectionを使うことでも
重複削除できる。

Main.java
import java.util.*;
import java.util.Comparator;
import java.util.stream.Collectors;
import java.util.stream.*;
public class Main {
public static void main(String[] args) throws Exception {
Person pob1 = new Person(1,"TANAKA","東京",11);
Person pob2 = new Person(2,"YAMADA","京都",12);
Person pob3 = new Person(3,"KOJIMA","東京",13);
Person pob4 = new Person(4,"MAJIMA","富山",13);
Person pob5 = new Person(4,"KOYAMA","東京",13);
List<Person>pList = new ArrayList<>();
pList.add(pob1);
pList.add(pob2);
pList.add(pob3);
pList.add(pob4);
pList.add(pob5);
//住所をキーにする
List<Person> unique = pList.stream().collect(Collectors.collectingAndThen(
Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(p->p.getAddress()))),
ArrayList::new));
//idをキーにする
List<Person> unique2 = pList.stream().collect(Collectors.collectingAndThen(
Collectors.toCollection(() -> new TreeSet<>(Comparator.comparingLong(p->p.getId()))),
ArrayList::new));
// 重複オブジェクト
System.out.println(unique);
System.out.println(unique2);
}
}
// [{2 YAMADA 京都 12}, {4 MAJIMA 富山 13}, {1 TANAKA 東京 11}]
// [{1 TANAKA 東京 11}, {2 YAMADA 京都 12}, {3 KOJIMA 東京 13}, {4 MAJIMA 富山 13}]

ちょっとわかりにくいような気もする。。。

動作確認

動作確認する

【java8】javaでのListの重複削除(Collectorsクラスを使用)

参考

重複したレコードを取得したい場合

重複しているレコードを削除ではなくで取得したい場合は
filterの中で同じlistに対してfilterして 重複しているレコードのみを抽出する

Main.java
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.*;
public class Main {
public static void main(String[] args) throws Exception {
//住所が重複してるオブジェクトを作成
Person pob1 = new Person(1,"TANAKA","東京",11);
Person pob2 = new Person(2,"YAMADA","京都",12);
Person pob3 = new Person(3,"KOJIMA","東京",13);
Person pob4 = new Person(3,"MAJIMA","富山",13);
Person pob5 = new Person(3,"KOYAMA","東京",13);
//listに追加
List<Person>pList = new ArrayList<>();
pList.add(pob1);
pList.add(pob2);
pList.add(pob3);
pList.add(pob4);
pList.add(pob5);
//重複オブジェクトの抽出
List<Person>resultList = pList.stream().filter(p1->{
List<Person>inList = pList.stream().filter(p2->p1.getAddress().equals(p2.getAddress())).collect(Collectors.toList());;
//2件以上あれば重複している
if(inList.size() > 1){
return true;
}else{
return false;
}
}).collect(Collectors.toList());
// 重複オブジェクト
System.out.println(resultList);
}
}
// [{1 TANAKA 東京 11}, {3 KOJIMA 東京 13}, {3 KOYAMA 東京 13}]
  • 重複しているオブジェクトのみを抽出できる

動作確認

【java8】javaでのListの重複抽出

重複してるかだけをチェックしたい場合

重複しているレコードを特定する必要がなく、ただ重複しているかだけ
確かめたい場合はdistinctを使う。

文字列のリスト

オブジェクトでないlistの場合はstreamのdistictを使うことで判定できる

Main.java
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.*;
public class Main {
public static void main(String[] args) throws Exception {
List<String>list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("aaa");
System.out.println(pList.size() == pList.stream().distinct().count());
// 重複要素が存在する場合false
}
}

オブジェクトのリストの場合はできないので重複したレコードを取得したい場合と同様に
するしかなさそう

まとめ

javaでコーディング時に重複チェック処理をstreamAPIを使ってできないかと思い
調べたり、考えてみたらできる方法があった。
Setを利用するなどの別のクラスの特性などを利用する方法は
まったく思いつかなかった。

参考書籍

新着記事

タグ別一覧
top