1. 概要

同じデータ型のオブジェクトのコレクション間の違いを見つけることは、一般的なプログラミングタスクです。 例として、試験に申し込んだ学生のリストと、試験に合格した学生の別のリストがあるとします。 これら2つのリストの違いにより、試験に合格しなかった学生がわかります。

Java では、 List APIの2つのリストの違いを明確に見つける方法はありませんが、いくつかのヘルパーメソッドが近づいています。

このクイックチュートリアルでは、2つのリストの違いを見つける方法を見ていきます。 プレーンなJava Streams の有無にかかわらず)やGuavaApacheCommonsCollections

2. テスト設定

例をテストするために使用する2つのリストを定義することから始めましょう。

public class FindDifferencesBetweenListsUnitTest {

    private static final List listOne = Arrays.asList("Jack", "Tom", "Sam", "John", "James", "Jack");
    private static final List listTwo = Arrays.asList("Jack", "Daniel", "Sam", "Alan", "James", "George");

}

3. JavaリストAPIの使用

ListメソッドremoveAll()を使用して、1つのリストのコピーを作成し、他のと共通のすべての要素を削除できます。

List<String> differences = new ArrayList<>(listOne);
differences.removeAll(listTwo);
assertEquals(2, differences.size());
assertThat(differences).containsExactly("Tom", "John");

これを逆にして、逆の違いを見つけましょう。

List<String> differences = new ArrayList<>(listTwo);
differences.removeAll(listOne);
assertEquals(3, differences.size());
assertThat(differences).containsExactly("Daniel", "Alan", "George");

また、2つのリストに共通する要素を見つけたい場合は、ListにもretainAllメソッドが含まれていることに注意してください。

4. StreamsAPIの使用

Java Stream は、コレクションからのデータに対して順次操作を実行するために使用できます。これには、リスト間の差異のフィルタリングが含まれます。

List<String> differences = listOne.stream()
            .filter(element -> !listTwo.contains(element))
            .collect(Collectors.toList());
assertEquals(2, differences.size());
assertThat(differences).containsExactly("Tom", "John");

最初の例のように、リストの順序を切り替えて、2番目のリストからさまざまな要素を見つけることができます。

List<String> differences = listTwo.stream()
            .filter(element -> !listOne.contains(element))
            .collect(Collectors.toList());
assertEquals(3, differences.size());
assertThat(differences).containsExactly("Daniel", "Alan", "George");

Listcontains()を繰り返し呼び出すと、大きなリストの場合、コストのかかる操作になる可能性があることに注意してください。

5. サードパーティライブラリの使用

5.1. GoogleGuavaを使用する

Guavaには便利なSets.differenceメソッドが含まれていますが、これを使用するには、最初にListSetに変換する必要があります。

List<String> differences = new ArrayList<>(Sets.difference(Sets.newHashSet(listOne), Sets.newHashSet(listTwo)));
assertEquals(2, differences.size());
assertThat(differences).containsExactlyInAnyOrder("Tom", "John");

ListSetに変換すると、複製を解除して並べ替える効果があることに注意してください。

5.2. ApacheCommonsCollectionsの使用

CollectionUtils class from Apache Commons Collections には、removeAllメソッドが含まれています。

このメソッドは、 List.removeAllと同じように実行しますが、結果の新しいコレクションも作成します。

List<String> differences = new ArrayList<>((CollectionUtils.removeAll(listOne, listTwo)));
assertEquals(2, differences.size());
assertThat(differences).containsExactly("Tom", "John");

6. 重複する値の処理

次に、2つのリストに重複する値が含まれている場合の違いを見つける方法を見てみましょう。

これを実現するには、最初のリストから重複する要素を削除する必要があります。正確には2番目のリストに含まれている要素の数だけです。

この例では、値“ Jack” が最初のリストに2回表示され、2番目のリストに1回だけ表示されます。

List<String> differences = new ArrayList<>(listOne);
listTwo.forEach(differences::remove);
assertThat(differences).containsExactly("Tom", "John", "Jack");

これは、 Apache CommonsCollectionssubtractメソッドを使用して実現することもできます。

List<String> differences = new ArrayList<>(CollectionUtils.subtract(listOne, listTwo));
assertEquals(3, differences.size());
assertThat(differences).containsExactly("Tom", "John", "Jack");

7. 結論

この記事では、リスト間の違いを見つけるためのいくつかの方法を検討しました

例では、基本的なJavaソリューション Streams APIを使用したソリューション、および GoogleGuavaApacheなどのサードパーティライブラリを使用したソリューションについて説明しました。 CommonsCollections。

また、重複する値を処理する方法も確認しました。

いつものように、完全なソースコードはGitHubから入手できます。