はじめに
この実験では、Java コレクション内の重複要素を効率的にチェックする方法を学びます。Java コレクションフレームワークの強力なツールである HashSet を使って重複を特定する方法を探ります。
実践的な手順を通じて、まず HashSet の要素の一意性を利用して重複を検出する方法を学びます。次に、元のコレクションとそれから作成した HashSet のサイズを比較することで、別の方法を見つけます。最後に、重複をチェックする際に null 要素をどう扱うかを調べます。
HashSet を使用した重複チェック
このステップでは、Java の HashSet を使ってコレクション内の重複要素を効率的にチェックする方法を探ります。HashSet は Java コレクションフレームワークの一部で、一意の要素を格納し、非常に高速な検索が可能なため特に便利です。
まず、~/project ディレクトリに DuplicateCheck.java という名前の新しい Java ファイルを作成しましょう。WebIDE のファイルエクスプローラーで、ファイルリストエリアを右クリックして「New File」を選択し、DuplicateCheck.java と入力することで作成できます。
次に、コードエディターで DuplicateCheck.java ファイルを開き、以下のコードを追加します。
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class DuplicateCheck {
public static void main(String[] args) {
// Create a list with some duplicate elements
List<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
names.add("Alice"); // Duplicate
names.add("Charlie");
names.add("Bob"); // Duplicate
System.out.println("Original List: " + names);
// Use a HashSet to find duplicates
Set<String> uniqueNames = new HashSet<>();
Set<String> duplicates = new HashSet<>();
for (String name : names) {
if (!uniqueNames.add(name)) {
// If add returns false, the element is already in the set
duplicates.add(name);
}
}
System.out.println("Duplicates found: " + duplicates);
}
}
このコードの新しい部分を分解してみましょう。
import java.util.ArrayList;,import java.util.HashSet;,import java.util.List;,import java.util.Set;: これらの行は、リストとセットを操作するために Java ユーティリティライブラリから必要なクラスをインポートします。List<String> names = new ArrayList<>();: これはStringオブジェクトを保持できるListであるnamesを作成します。Listインターフェースの具体的な実装としてArrayListを使用しています。names.add(...): これはnamesリストに要素を追加します。「Alice」と「Bob」が 2 回追加されていることに注意してください。Set<String> uniqueNames = new HashSet<>();: これはHashSet実装を使用してuniqueNamesというSetを作成します。Setは一意の要素のみを含むことを保証します。Set<String> duplicates = new HashSet<>();: これは見つかった重複要素を格納するための別のSetを作成します。for (String name : names): これはnamesリスト内の各nameを反復処理するfor-eachループです。if (!uniqueNames.add(name)):HashSetのadd()メソッドは、要素が正常に追加された場合(つまり、セット内にまだ存在しなかった場合)はtrueを返し、要素がすでに存在する場合はfalseを返します。!は結果を反転させるため、ifブロック内のコードはadd()がfalseを返すとき、つまり重複があるときにのみ実行されます。duplicates.add(name);: 重複が見つかった場合、それをduplicatesセットに追加します。
DuplicateCheck.java ファイルを保存します(Ctrl+S または Cmd+S)。
次に、WebIDE の下部にあるターミナルを開きます。~/project ディレクトリにいることを確認してください。pwd と入力して Enter キーを押すことで確認できます。出力は /home/labex/project であるはずです。
javac コマンドを使用して Java プログラムをコンパイルします。
javac DuplicateCheck.java
エラーがなければ、何も出力されないはずです。これはコンパイルが成功し、~/project ディレクトリに DuplicateCheck.class ファイルが作成されたことを意味します。ls コマンドを実行することで確認できます。
最後に、java コマンドを使用してコンパイルされた Java プログラムを実行します。
java DuplicateCheck
以下のような出力が表示されるはずです。
Original List: [Alice, Bob, Alice, Charlie, Bob]
Duplicates found: [Alice, Bob]
HashSet は挿入順序を保持しないため、「Duplicates found」の出力における要素の順序は異なる場合があります。
あなたは HashSet を使ってリスト内の重複要素を正常に特定することができました!
コレクションとセットのサイズを比較する
前のステップでは、HashSet を使って重複要素を見つけました。Set の重要な特性は、一意の要素のみを格納することです。つまり、Set に重複要素を追加すると、各要素のインスタンスは 1 つだけ保持されます。この特性は、リストから重複を削除するなどのタスクに非常に便利です。
このステップでは、元のリスト(重複要素を含む可能性があります)のサイズと、そのリストから作成された HashSet(一意の要素のみを含みます)のサイズを比較することで、この特性を示すように DuplicateCheck.java プログラムを修正します。
WebIDE のコードエディターで DuplicateCheck.java ファイルを開きます。
main メソッドを以下のように修正します。
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class DuplicateCheck {
public static void main(String[] args) {
// Create a list with some duplicate elements
List<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
names.add("Alice"); // Duplicate
names.add("Charlie");
names.add("Bob"); // Duplicate
names.add("David");
System.out.println("Original List: " + names);
System.out.println("Size of Original List: " + names.size());
// Create a HashSet from the list
Set<String> uniqueNamesSet = new HashSet<>(names);
System.out.println("Set created from List: " + uniqueNamesSet);
System.out.println("Size of Set: " + uniqueNamesSet.size());
// The difference in size tells us how many duplicates were removed
int duplicatesCount = names.size() - uniqueNamesSet.size();
System.out.println("Number of duplicates (excluding first occurrence): " + duplicatesCount);
}
}
追加または変更した部分は次のとおりです。
namesリストに別の名前「David」を追加して、少し大きなリストにしました。System.out.println("Size of Original List: " + names.size());:size()メソッドを使って元のリストのサイズを出力します。Set<String> uniqueNamesSet = new HashSet<>(names);: これは別のCollection(ここではArrayList)から直接HashSetを作成する便利な方法です。このようにすると、HashSetは自動的にリストのすべての要素を追加し、Setであるため、重複要素は破棄されます。System.out.println("Size of Set: " + uniqueNamesSet.size());:HashSetのサイズを出力します。このサイズは一意の要素の数を表します。int duplicatesCount = names.size() - uniqueNamesSet.size();: リストのサイズとセットのサイズの差を計算します。この差は、(最初の出現を除いた)重複要素の数を示します。
修正した DuplicateCheck.java ファイルを保存します。
次に、ターミナルでプログラムを再度コンパイルします。
javac DuplicateCheck.java
コンパイルが成功したら、プログラムを実行します。
java DuplicateCheck
以下のような出力が表示されるはずです。
Original List: [Alice, Bob, Alice, Charlie, Bob, David]
Size of Original List: 6
Set created from List: [Alice, Bob, Charlie, David]
Size of Set: 4
Number of duplicates (excluding first occurrence): 2
元のリストのサイズは 6 ですが、それから作成された HashSet のサイズは 4 であることに注意してください。差(6 - 4 = 2)は、2 つの重複名(「Alice」と「Bob」が最初の出現後にそれぞれ 1 回ずつ登場した)があったことを正しく示しています。
これは、HashSet を使ってコレクション内の一意の要素の数や重複要素の数を簡単に見つけることができることを示しています。
null 要素でテストする
前のステップでは、HashSet が非ヌルの重複要素をどのように扱うかを見てきました。今度は、null 要素を追加しようとしたときの HashSet の動作を調べてみましょう。コレクションが null をどのように扱うかを理解することは重要です。なぜなら、注意深く扱わないと、予期しない動作やエラーにつながることがあるからです。
HashSet は 1 つの null 要素を許可します。null を複数回追加しようとすると、最初の null のみが格納されます。
これをテストするために、DuplicateCheck.java プログラムをもう一度修正しましょう。
WebIDE のコードエディターで DuplicateCheck.java ファイルを開きます。
main メソッドを修正して、リストに null 値を含めます。
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class DuplicateCheck {
public static void main(String[] args) {
// Create a list with some duplicate and null elements
List<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
names.add(null); // Add null
names.add("Alice"); // Duplicate
names.add("Charlie");
names.add(null); // Add null again
names.add("Bob"); // Duplicate
names.add("David");
names.add(null); // Add null a third time
System.out.println("Original List: " + names);
System.out.println("Size of Original List: " + names.size());
// Create a HashSet from the list
Set<String> uniqueNamesSet = new HashSet<>(names);
System.out.println("Set created from List: " + uniqueNamesSet);
System.out.println("Size of Set: " + uniqueNamesSet.size());
// The difference in size tells us how many duplicates were removed
// Note: This calculation is less straightforward with nulls and duplicates combined
// int duplicatesCount = names.size() - uniqueNamesSet.size();
// System.out.println("Number of duplicates (excluding first occurrence): " + duplicatesCount);
}
}
ここでは、names リストに複数回 null を追加しています。また、null が含まれる場合、重複数の計算があまり意味を持たなくなるため、重複数の計算部分をコメントアウトしています。今回は null を含めたセットの動作に焦点を当てています。
修正した DuplicateCheck.java ファイルを保存します。
ターミナルでプログラムをコンパイルします。
javac DuplicateCheck.java
コンパイルが成功したら、プログラムを実行します。
java DuplicateCheck
以下のような出力が表示されるはずです。
Original List: [Alice, Bob, null, Alice, Charlie, null, Bob, David, null]
Size of Original List: 9
Set created from List: [null, Alice, Bob, Charlie, David]
Size of Set: 5
出力を見てみましょう。
Original Listには、複数のnull値を含むすべての要素が表示されています。そのサイズは 9 です。Set created from Listには一意の要素のみが含まれています。リストに複数回nullが追加されていても、セット内ではnullが 1 回だけ表示されていることに注意してください。セットのサイズは 5(Alice、Bob、Charlie、David、および null)です。
これにより、HashSet が 1 つの null 要素を許可し、それ以降の null の追加を他の要素と同じように重複として扱うことが確認できます。
これで、HashSet が null 要素をどのように扱うかを正常にテストできました。これで、HashSet を使った重複チェックと、一意の要素および null 要素に対する動作の調査は終了です。
まとめ
この実験では、Java のコレクション内の重複要素を HashSet を使って効率的にチェックする方法を学びました。重複要素を含む List を作成し、それを反復処理して、各要素を HashSet に追加しようとしました。add() メソッドの戻り値をチェックすることで、要素がすでに存在する場合は false を返すため、重複要素を識別して別の HashSet に収集することができました。この方法は、HashSet の一意の要素特性と高速な検索機能を利用して、効果的な重複検出を行います。



