Javaでマップ(Map)を値順にソートする方法【サンプルコード付き】
この記事では、Javaでマップ(Map)を値(Value)を基準にソートする方法を解説します。JavaのHashMapは、Mapインターフェースをハッシュテーブルベースで実装したクラスであり、キーと値のペアを格納するコレクションです。
なお、HashMapは要素の順序を保持しないため、値の順序どおりに出力したい場合は、ソート結果をLinkedHashMapに格納するのがポイントです。まずは、具体的な動作例から見ていきましょう。
たとえば、次のようなHashMapがあったとします。
入力:
Input HashMap: Key = Java, Value = 45 Key = Scala, Value = 20 Key = Mysql, Value = 11 Key = Python, Value = 75
期待される出力(値の昇順):
The HashMap after sorting is: Key = Mysql, Value = 11 Key = Scala, Value = 20 Key = Java, Value = 45 Key = Python, Value = 75
ソートの手順(アルゴリズム)
ステップ1 - 処理を開始する ステップ2 - 必要な変数やクラスを宣言する ステップ3 - キーと値を定義する ステップ4 - 「sort」メソッドを使ってマップの要素をソートする ステップ5 - 「getValue」メソッドで値を取得し、「compareTo」メソッドで2つの値を比較する ステップ6 - ハッシュマップを走査し、「getKey」メソッドで要素を「temp」に格納する。「temp」を戻り値として返す ステップ7 - 結果を表示する ステップ8 - 処理を終了する
例1:ソート処理を独立したメソッドとして定義する
最初の例では、ソート処理を「sort」メソッドとして切り出し、mainメソッドから呼び出す形で実装します。エントリー集合をLinkedListに変換し、Comparatorで値を比較しながら並べ替えるのが基本の流れです。
import java.util.*;
import java.lang.*;
public class Demo {
public static HashMap<String, Integer> sort(HashMap<String, Integer> input_map){
List<Map.Entry<String, Integer> > list =
new LinkedList<Map.Entry<String, Integer> >(input_map.entrySet());
Collections.sort(list, new Comparator<Map.Entry<String, Integer> >() {
public int compare(Map.Entry<String, Integer> o1,
Map.Entry<String, Integer> o2){
return (o1.getValue()).compareTo(o2.getValue());
}
});
HashMap<String, Integer> temp = new LinkedHashMap<String, Integer>();
for (Map.Entry<String, Integer> aa : list) {
temp.put(aa.getKey(), aa.getValue());
}
return temp;
}
public static void main(String[] args){
HashMap<String, Integer> input_map = new HashMap<String, Integer>();
input_map.put("Java", 45);
input_map.put("Scala", 20);
input_map.put("Mysql", 11);
input_map.put("Python", 75);
System.out.println("The HashMap is defined as:");
for (Map.Entry<String, Integer> element : input_map.entrySet()) {
System.out.println("Key = " + element.getKey() + ", Value = " + element.getValue());
}
Map<String, Integer> result_map = sort(input_map);
System.out.println("\nThe HashMap after sorting is:");
for (Map.Entry<String, Integer> element : result_map.entrySet()) {
System.out.println("Key = " + element.getKey() + ", Value = " + element.getValue());
}
}
}
出力
The HashMap is defined as: Key = Java, Value = 45 Key = Scala, Value = 20 Key = Mysql, Value = 11 Key = Python, Value = 75 The HashMap after sorting is: Key = Mysql, Value = 11 Key = Scala, Value = 20 Key = Java, Value = 45 Key = Python, Value = 75
例2:すべての処理をmainメソッド内に直接記述する
次の例では、ソート処理を別メソッドに分けず、mainメソッドの中に直接記述しています。小規模な処理であれば、こちらの方がシンプルに書けるでしょう。
import java.util.*;
import java.lang.*;
public class Demo {
public static void main(String[] args){
HashMap<String, Integer> input_map = new HashMap<String, Integer>();
input_map.put("Java", 45);
input_map.put("Scala", 20);
input_map.put("Mysql", 11);
input_map.put("Python", 75);
System.out.println("The HashMap is defined as:");
for (Map.Entry<String, Integer> element : input_map.entrySet()) {
System.out.println("Key = " + element.getKey() + ", Value = " + element.getValue());
}
List<Map.Entry<String, Integer> > list =
new LinkedList<Map.Entry<String, Integer> >(input_map.entrySet());
Collections.sort(list, new Comparator<Map.Entry<String, Integer> >() {
public int compare(Map.Entry<String, Integer> o1,
Map.Entry<String, Integer> o2){
return (o1.getValue()).compareTo(o2.getValue());
}
});
HashMap<String, Integer> result_map = new LinkedHashMap<String, Integer>();
for (Map.Entry<String, Integer> aa : list) {
result_map.put(aa.getKey(), aa.getValue());
}
System.out.println("\nThe HashMap after sorting is:");
for (Map.Entry<String, Integer> element : result_map.entrySet()) {
System.out.println("Key = " + element.getKey() + ", Value = " + element.getValue());
}
}
}
出力
The HashMap is defined as: Key = Java, Value = 45 Key = Scala, Value = 20 Key = Mysql, Value = 11 Key = Python, Value = 75 The HashMap after sorting is: Key = Mysql, Value = 11 Key = Scala, Value = 20 Key = Java, Value = 45 Key = Python, Value = 75
補足:Java 8以降ならStream APIでより簡潔に書ける
Java 8以降を使用している場合は、Stream APIを活用することで、Comparatorの無名クラスをラムダ式やメソッド参照に置き換えられます。次のように書くと、よりモダンで読みやすいコードになります。
import java.util.*;
import java.util.stream.Collectors;
Map<String, Integer> sorted = input_map.entrySet()
.stream()
.sorted(Map.Entry.comparingByValue())
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(e1, e2) -> e1,
LinkedHashMap::new));
実装のポイント
- HashMapは順序を保持しない:そのままでは値順に並ばないため、ソート済みのエントリーをLinkedHashMapに再格納します。
- LinkedHashMapを選ぶ理由:要素を挿入した順序を保持できるため、ソート結果がそのまま維持されます。
- 降順にソートしたい場合:compareメソッドの戻り値に「-1」を掛けるか、「o2.getValue().compareTo(o1.getValue())」と比較の向きを逆にすればOKです。
まとめ
Javaでマップを値順にソートするには、①entrySet()をListに変換 → ②Comparatorで値を比較してソート → ③LinkedHashMapに再格納、という流れが基本となります。Java 8以降の環境であれば、Stream APIの「comparingByValue()」を使うことで、さらに簡潔に記述できます。プロジェクトの要件やJavaのバージョンに応じて、最適な方法を選んでみてください。
-
Javaで実装するカクテルソート(双方向バブルソート)のプログラム
カクテルソート(Cocktail Sort)は、バブルソートを改良した整列アルゴリズムの一つで、「双方向バブルソート」や「シェーカーソート」とも呼ばれます。通常のバブルソートが配列を一方向にのみ走査するのに対し、カクテルソートは前方向と後方向を交互に走査する点が最大の特徴です。まず前方向のパスでは、隣り合う要素を比較しながら大きい値を配列の末尾側へ移動させます。続く後方向のパスでは、逆に小さい値を配列の先頭側へ移動させます。この往復操作を、交換が一度も発生しなくなるまで繰り返すことで、配列全体が昇順に整列されます。この手法により、配列の終盤に位置する小さな要素でも、1回の後方向パスで先頭付近ま
-
カクテルソートとは?Javaでの実装方法と動作原理をわかりやすく解説
カクテルソート(Cocktail Sort)は、バブルソートを改良した整列アルゴリズムの一つで、「双方向バブルソート」や「シェーカーソート」とも呼ばれます。通常のバブルソートでは、要素を左から右への一方向にのみ走査し、大きい値から順に配列の末尾へ確定させていきます。一方、カクテルソートでは左から右、右から左へと交互に双方向の走査を行う点が大きな特徴です。これにより、配列の末尾側だけでなく先頭側にも素早く整列済みの領域が形成され、バブルソートよりも効率が向上する場合があります。カクテルソートのJavaプログラム例以下は、カクテルソートをJavaで実装したサンプルプログラムです。public cl