HOWTO · Java
Java で HashMap をキーで並べ替える
この記事では、Java で HashMap をキーでソートする方法を紹介します。
このページの内容
Java 言語の HashMap という用語は、Map インターフェースから派生したコレクションです。このコレクションまたはクラスは java.util パッケージに含まれており、データをキーと値のペアで格納します。マップ上に 2つのキーを含めることはできないことに注意してください。重複するキーが挿入されると、それぞれのキーの値が新しい値に置き換えられます。
Java の TreeMap クラスを使用してキーセットを並べ替える
以下は、HashMap をキーでソートする方法を示すコードブロックです。
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
public class HashMapSortByKey {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("2", "Value5");
map.put("3", "Value1");
map.put("1", "Value2");
map.put("4", "Value3");
map.put("9", "Value4");
map.put("hi11", "Value6");
map.put("hi0", "Value7");
System.out.print("Unordered List: ");
for (String s : map.keySet()) {
System.out.print(" " + s);
}
System.out.println();
System.out.print("Ordered List: ");
TreeMap<String, String> map1 = new TreeMap<>(map);
for (String s : map1.keySet()) {
System.out.print(" " + s);
}
}
}
上記のコードブロックでは、map オブジェクトは、new キーワードを指定した HashMap のデフォルトコンストラクターを使用して宣言されています。このステートメントは、HashSet クラスのインスタンスを作成し、その値を Map インターフェイス参照に割り当てます。HashMap クラスは Map インターフェースを内部的に実装するため、タイプは互換性があります。
マップは、いくつかのキー値のセットで初期化されます。挿入は、キーを指定された値にバインドする put メソッドを使用して行われます。キーがマップにすでに存在する場合、メソッドは previous value を返し、前の値を指定された値でオーバーライドします。キーがマップにまだ存在しない場合、関数は null 値を返します。キーまたは値のプロパティで値の挿入が禁止されている場合は、IllegalArgumentException がスローされます。
マップを反復処理するために、for-each ループが使用されます。map.keySet 関数は、マップ内のすべてのキーの Set 形式を返します。キーセット関数は、変数が反復できる for-each ループでコレクションを取得します。したがって、キーを出力します。値は順序付けられていない形式で出力され、ユーザーが出力を取得する明確な方法はありません。
マップキーをソートするために、TreeSet クラスが使用されます。map 変数は、インスタンス化時に TreeSet コンストラクターのコンストラクターパラメーターとして指定されます。このクラスは、キーをソートするための Comparable インターフェースを実装しています。結果のマップ map1 が出力されると、ソートされたキーが出力に出力されます。
以下は、上記のコードブロックの出力です。
出力:
Unordered List: 1 hi11 2 3 4 9 hi0
Ordered List: 1 2 3 4 9 hi0 hi11
Java 8 関数を使用したキーセットのソート
Java 8 は、関数型プログラミングの特権を提供します。これは、チェーン関数の操作に役立ちます。以下のプログラムでは、インスタンス化と初期化がステートメントで行われていることがわかります。一方、最初のサンプルコードでは、マップにデータを入力するのは面倒な作業です。単一のステートメントでマップをインスタンス化するための Stream と関数の理解を以下に示します。
Streams は java.util パッケージのインターフェースであり、操作のシーケンスを一度に処理する柔軟性を提供します。Streams は、エミッターがデータを送信するパイプラインで機能します。ユーザーのニーズに応じて、フィルタリング、処理、変換などが行われます。
import static java.util.AbstractMap.SimpleEntry;
import static java.util.stream.Collectors.toMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Stream;
public class HashMapSortByKey {
public static void main(String[] args) {
Map<String, String> map =
Stream
.of(new SimpleEntry<>("key6", "value1"), new SimpleEntry<>("key12", "value2"),
new SimpleEntry<>("key9", "value3"))
.collect(toMap(SimpleEntry::getKey, SimpleEntry::getValue));
System.out.print("Unordered List: ");
for (String s : map.keySet()) {
System.out.print(" " + s);
}
Map<String, String> mapSortedByKey =
map.entrySet()
.stream()
.sorted(Map.Entry.<String, String>comparingByKey().reversed())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
(oldVal, newValue) -> oldValue, LinkedHashMap::new));
System.out.println();
System.out.print("Ordered List: ");
for (String s1 : mapSortedByKey.keySet()) {
System.out.print(" " + s1);
}
}
}
Java のマップ初期化ストリーム関数を理解する
まず、Stream は、指定されたストリームを順番に返す of() 関数を呼び出します。この関数は、SimpleEntry クラスのオブジェクトを作成して、Key-Value フォームのマッピングを作成します。このクラスは Entry インターフェースを実装し、マップのコレクションビューを返す entrySet メソッドを持っています。
Key-Value エントリが形成されると、collect 関数を使用して値がマップに収集されます。これはターミナル関数であり、collect 関数の後にメソッドを呼び出すことはできません。この関数は、ストリーム値を目的のデータ構造にパッケージ化またはバインドします。
パラメータとして指定された入力は、常に Collector 参照です。toMap は、マップ内のストリーム要素をバインドする Collector を返す Collectors クラスの静的関数です。この関数は、キーマッパーとキー値関数をパラメーターとして受け取ります。ここで、メソッド参照::演算子は、指定されたクラスの関数を呼び出すことを意味します。
キーマッパーでは、getKey 関数が入力された EntrySet ストリームからキーを抽出します。同様に、Key Value 関数では、getValue 関数が呼び出されて、EntrySet ストリームから値を取得します。
上記のコードの Collector``Function 変数は、機能のための単一の抽象メソッドを持つ Java の機能インターフェイスです。抽象メソッドの定義は、それらを実装するクラスで定義されます。
Java のマップ変換ストリーム関数を理解する
形成されたばかりの map インスタンス上で、entrySet 関数が呼び出されます。この関数は、マップエントリのセットビューを返し、マップインターフェイスに存在します。これらのエントリに対して、stream メソッドが呼び出され、シーケンシャルストリームのエントリが変換されます。エントリのストリームを介して、sorted 関数が呼び出されます。
Stream 要素を比較するには、コンパレータが必要です。ソートされた関数は、最終的に、指定されたエントリのソートされたストリームを返します。comparingByKey 関数は、キーのデフォルトの順序で Map.Entry コンパレータを返します。コンパレータはキーセットを返します。見つかったキーが null の場合、関数から NullPointerException がスローされます。
エントリセットが取得されると、コレクション内の要素の順序を逆にするために reversed 関数が呼び出されます。最後に、collect 関数がマップストリームを介して呼び出されます。この関数は端末演算子であるため、collect 関数の後に操作を呼び出すことはできません。関数内で、toMap 関数が呼び出され、ストリームがマップに変換されます。
この関数は 4つのパラメーターを取ります。keyMapper はキーを生成する関数、valueMapper はその値を作成するマッピング関数、mergeFunction は関数をマージする BinaryOperator、mapSupplier は結果が挿入される新しい空のマップを返す Supplier 関数。最後に、結果のコンソール出力が上に出力されます。
出力:
Unordered List: key12 key6 key9
Ordered List: key9 key6 key12