はじめに
この実験では、Java の List に重複する要素が含まれているかどうかを効率的にチェックする方法を学びます。HashSet データ構造を使用した一般的で効果的な手法を探ります。
まず、HashSet の要素の一意性を利用して、リストを反復処理しながら要素をセットに追加することで重複を検出するメソッドを実装します。セットにすでに要素が存在する場合、重複が見つかったことになります。その後、元のリストのサイズと、リストの要素で満たされた HashSet のサイズを比較することで、別のアプローチを学びます。最後に、null リストや空のリストを含むさまざまなシナリオで実装をテストし、堅牢性を確保します。
HashSet を使用した重複検出
このステップでは、Java の HashSet を使用してコレクション内の重複要素を効率的に検出する方法を探ります。HashSet は Java コレクションフレームワークの一部で、一意の要素を格納するのに特に便利です。
まず、~/project ディレクトリに DuplicateDetector.java という名前の新しい Java ファイルを作成しましょう。これは、左側の WebIDE のファイルエクスプローラーを使用して行うことができます。~/project 領域で右クリックし、「New File」を選択して DuplicateDetector.java と入力します。
次に、コードエディターで DuplicateDetector.java ファイルを開き、以下のコードを追加します。
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class DuplicateDetector {
public static boolean containsDuplicates(List<String> list) {
// Create a HashSet to store unique elements
Set<String> uniqueElements = new HashSet<>();
// Iterate through the list
for (String element : list) {
// If the element is already in the HashSet, it's a duplicate
if (uniqueElements.contains(element)) {
return true; // Found a duplicate
}
// Otherwise, add the element to the HashSet
uniqueElements.add(element);
}
// If the loop finishes without finding duplicates, return false
return false;
}
public static void main(String[] args) {
// Example usage
List<String> myListWithDuplicates = new ArrayList<>();
myListWithDuplicates.add("apple");
myListWithDuplicates.add("banana");
myListWithDuplicates.add("apple"); // Duplicate
myListWithDuplicates.add("orange");
List<String> myListWithoutDuplicates = new ArrayList<>();
myListWithoutDuplicates.add("grape");
myListWithoutDuplicates.add("mango");
myListWithoutDuplicates.add("kiwi");
System.out.println("List with duplicates: " + myListWithDuplicates);
System.out.println("Contains duplicates? " + containsDuplicates(myListWithDuplicates)); // Expected: true
System.out.println("\nList without duplicates: " + myListWithoutDuplicates);
System.out.println("Contains duplicates? " + containsDuplicates(myListWithoutDuplicates)); // Expected: false
}
}
このコードの重要な部分を理解しましょう。
import java.util.ArrayList;,import java.util.HashSet;,import java.util.List;,import java.util.Set;: これらの行は、Java コレクションフレームワークから必要なクラスをインポートします。public static boolean containsDuplicates(List<String> list): これは、StringオブジェクトのListを入力として受け取り、重複が含まれている場合はtrueを返し、そうでない場合はfalseを返すメソッドです。Set<String> uniqueElements = new HashSet<>();: これはuniqueElementsという名前の空のHashSetを作成します。HashSetは一意の要素のみを格納するように設計されています。for (String element : list): このループは、入力listの各elementを反復処理します。if (uniqueElements.contains(element)): これは、現在のelementがuniqueElementsHashSetにすでに存在するかどうかをチェックします。存在する場合、重複が見つかったことになり、メソッドはtrueを返します。uniqueElements.add(element);: 要素がHashSetにまだ存在しない場合、追加されます。HashSetは一意の要素のみを格納するため、すでに存在する要素を追加しても効果はありません。return false;: ループが重複を見つけずに完了した場合、メソッドはfalseを返します。mainメソッドは、サンプルリストを使用してcontainsDuplicatesメソッドを使用する方法を示しています。
DuplicateDetector.java ファイルを保存します(Ctrl+S または Cmd+S)。
次に、ターミナルでこのプログラムをコンパイルして実行しましょう。~/project ディレクトリにいることを確認してください。
コードをコンパイルします。
javac DuplicateDetector.java
コンパイルエラーがない場合、出力は表示されません。
次に、コンパイルされたコードを実行します。
java DuplicateDetector
以下のような出力が表示されるはずです。
List with duplicates: [apple, banana, apple, orange]
Contains duplicates? true
List without duplicates: [grape, mango, kiwi]
Contains duplicates? false
この出力は、containsDuplicates メソッドが重複のあるリストを正しく識別したことを確認しています。HashSet を使用することは、重複をチェックする効率的な方法です。なぜなら、HashSet 内に要素が存在するかどうかをチェックする(contains() を使用する)のは、平均的に非常に高速だからです。
リストのサイズとセットのサイズを比較する
前のステップでは、リストを反復処理して要素をセットに追加することで、HashSet を使用して重複をチェックしました。重複を検出するより簡単で、多くの場合、より効率的な方法は、元のリストのサイズと、そのリストから作成された HashSet のサイズを比較することです。
HashSet は一意の要素のみを格納することを思い出してください。リストに重複が含まれている場合、そのリストから作成された HashSet のサイズは、元のリストのサイズよりも小さくなります。重複がない場合、サイズは同じになります。
このアプローチを実装するために、DuplicateDetector.java ファイルを変更しましょう。コードエディターで ~/project/DuplicateDetector.java を開きます。
containsDuplicates メソッドを以下のコードに置き換えます。
public static boolean containsDuplicates(List<String> list) {
// Create a HashSet from the list
Set<String> uniqueElements = new HashSet<>(list);
// Compare the size of the list with the size of the HashSet
return list.size() != uniqueElements.size();
}
新しいコードでは以下のことが行われています。
Set<String> uniqueElements = new HashSet<>(list);: この行は、入力listのすべての要素でHashSetを直接作成し、初期化します。HashSetは自動的に一意性を処理するため、リスト内の重複要素はセットに追加されません。return list.size() != uniqueElements.size();: この行は、元のlistの要素数 (list.size()) とHashSetの一意の要素数 (uniqueElements.size()) を比較します。サイズが異なる場合 (!=)、リストに重複があったことを意味し、メソッドはtrueを返します。サイズが同じ場合、重複はなく、メソッドはfalseを返します。
main メソッドは、すでに containsDuplicates メソッドを呼び出しているため、同じままにすることができます。
DuplicateDetector.java ファイルを保存します(Ctrl+S または Cmd+S)。
次に、変更したプログラムをコンパイルして実行しましょう。ターミナルで ~/project ディレクトリにいることを確認してください。
コードをコンパイルします。
javac DuplicateDetector.java
コンパイルされたコードを実行します。
java DuplicateDetector
前と同じ出力が表示されるはずです。
List with duplicates: [apple, banana, apple, orange]
Contains duplicates? true
List without duplicates: [grape, mango, kiwi]
Contains duplicates? false
これは、サイズ比較を使用した新しい、より簡単な重複検出方法が正しく機能することを確認しています。このアプローチは一般的により簡潔で、特に大きなリストの場合、1 つずつ反復処理して包含をチェックするよりも効率的です。
null リストと空のリストでテストする
実際のプログラミングでは、リストが空である場合や null である場合などのエッジケースを考慮することが重要です。現在の containsDuplicates メソッドは要素のあるリストに対してはうまく機能しますが、空のリストや null のリストを渡した場合はどうなるでしょうか。
~/project/DuplicateDetector.java の main メソッドにさらに例を追加してこれをテストしましょう。コードエディターでファイルを開き、既存のコードの後に以下の行を main メソッドに追加します。
System.out.println("\nEmpty list: " + new ArrayList<>());
System.out.println("Contains duplicates? " + containsDuplicates(new ArrayList<>())); // Expected: false
List<String> nullList = null;
System.out.println("\nNull list: " + nullList);
// The following line will cause a NullPointerException if not handled
// System.out.println("Contains duplicates? " + containsDuplicates(nullList));
ファイルを保存します(Ctrl+S または Cmd+S)。
次に、プログラムを再度コンパイルして実行します。
コンパイル:
javac DuplicateDetector.java
実行:
java DuplicateDetector
空のリストの出力が表示されるはずです。
List with duplicates: [apple, banana, apple, orange]
Contains duplicates? true
List without duplicates: [grape, mango, kiwi]
Contains duplicates? false
Empty list: []
Contains duplicates? false
空のリストの出力は正しいです。空のリストには重複がありません。
ただし、System.out.println("Contains duplicates? " + containsDuplicates(nullList)); の行のコメントを外してコンパイルして実行すると、NullPointerException が発生します。これは、null のリストから HashSet を作成しようとしているためで、これは許可されていません。
containsDuplicates メソッドをより堅牢にするために、入力リストが null の場合を処理する必要があります。メソッドの冒頭にチェックを追加することができます。
~/project/DuplicateDetector.java の containsDuplicates メソッドを変更して、null チェックを含めます。
public static boolean containsDuplicates(List<String> list) {
// Handle null input
if (list == null) {
return false; // A null list does not contain duplicates
}
// Create a HashSet from the list
Set<String> uniqueElements = new HashSet<>(list);
// Compare the size of the list with the size of the HashSet
return list.size() != uniqueElements.size();
}
次に、main メソッドで null リストをテストする行のコメントを外します。
List<String> nullList = null;
System.out.println("\nNull list: " + nullList);
System.out.println("Contains duplicates? " + containsDuplicates(nullList)); // Expected: false
ファイルを保存します(Ctrl+S または Cmd+S)。
最後に一度、プログラムをコンパイルして実行します。
コンパイル:
javac DuplicateDetector.java
実行:
java DuplicateDetector
出力には、クラッシュすることなく null リストの結果が含まれるはずです。
List with duplicates: [apple, banana, apple, orange]
Contains duplicates? true
List without duplicates: [grape, mango, kiwi]
Contains duplicates? false
Empty list: []
Contains duplicates? false
Null list: null
Contains duplicates? false
null チェックを追加することで、containsDuplicates メソッドはより堅牢になり、null 入力を適切に処理できるようになりました。これは、予期しないエラーを防ぐための重要なプログラミングの実践です。
まとめ
この実験では、Java の List に重複要素が含まれているかどうかをチェックする方法を学びました。効率的な重複検出のために HashSet を使用する方法を調べました。リストを反復処理し、各要素を HashSet に追加しようとすることで、要素がすでに存在するかどうかをすばやく判断でき、重複を検出できます。
また、元のリストのサイズと、そのリストから作成された HashSet のサイズを比較することで、別の方法も学びました。サイズが異なる場合、重複が存在することを示します。最後に、堅牢性を確保するために、null リストと空のリストでメソッドをテストすることで、エッジケースを考慮しました。



