JavaでHashMapをソートする
1前書き
このクイックチュートリアルでは、** Javaで
HashMap
をソートする方法を学びます。
具体的には、次のようにして
HashMap
エントリをキーまたは値でソートする方法を見ていきます。
-
TreeMap
-
ArrayList
および
Collections.sort()
-
TreeSet
-
Stream
APIの使用
__、
__そして最後に、 -
__Guava
__libraryの使用
2
TreeMap
を使う
私たちが知っているように、
TreeMap
の
キーはそれらの自然な順序
を使ってソートされています。
キーと値のペアをキーでソートしたい場合、これは良い解決策です。つまり、すべてのデータを
HashMap
からhttps://www.baeldung.com/java-treemap[
TreeMap
]にプッシュすることです。
まず始めに、
HashMap
を定義し、それをデータで初期化しましょう:
Map<String, Employee> map = new HashMap<>();
Employee employee1 = new Employee(1L, "Mher");
map.put(employee1.getName(), employee1);
Employee employee2 = new Employee(22L, "Annie");
map.put(employee2.getName(), employee2);
Employee employee3 = new Employee(8L, "John");
map.put(employee3.getName(), employee3);
Employee employee4 = new Employee(2L, "George");
map.put(employee4.getName(), employee4);
Employee
クラスの場合、
Comparable
:** が実装されていることに注意してください。
public class Employee implements Comparable<Employee> {
private Long id;
private String name;
//constructor, getters, setters
//override equals and hashCode
@Override
public int compareTo(Employee employee) {
return (int)(this.id - employee.getId());
}
}
次に、コンストラクタを使ってエントリを
__TreeMap
__byに格納します。
TreeMap<String, Employee> sorted = new TreeMap<>(map);
または、
putAll
メソッドでデータをコピーします。
TreeMap<String, Employee> sorted = new TreeMap<>();
sorted.putAll(map);
以上です!マップのエントリがキーでソートされていることを確認するために、それらを印刷してみましょう。
Annie=Employee{id=22, name='Annie'}
George=Employee{id=2, name='George'}
John=Employee{id=8, name='John'}
Mher=Employee{id=1, name='Mher'}
ご覧のとおり、キーは自然な順序で並べ替えられています。
3
ArrayList
を使用する
もちろん、
ArrayList
を使用してマップのエントリを並べ替えることができます。前の方法との主な違いは、
Map
インターフェースをここでは保守しないことです。
3.1. キー順で並べ替え
キーセットを
ArrayList
にロードしましょう。
List<String> employeeByKey = new ArrayList<>(map.keySet());
Collections.sort(employeeByKey);
そして出力は次のとおりです。
----[Annie, George, John, Mher]----
3.2. 値で並べ替え
それでは、マップ値を
Employee
オブジェクトの
id
フィールドで並べ替える場合はどうなりますか。そのためにも
ArrayList
を使用できます。
まず、値をリストにコピーしましょう。
List<Employee> employeeById = new ArrayList<>(map.values());
その後、並べ替えます。
Collections.sort(employeeById);
-
Employee
が
Comparable
インターフェース** を実装しているので、これはうまくいくことを忘れないでください。それ以外の場合は、
Collections.sort
を呼び出すための手動コンパレータを定義する必要があります。
結果を確認するために、
employeeById
を印刷します。
----[Employee{id=1, name='Mher'},
Employee{id=2, name='George'},
Employee{id=8, name='John'},
Employee{id=22, name='Annie'}]----
ご覧のとおり、オブジェクトは
id
フィールドでソートされています。
4
TreeSet
を使う
ソートされたコレクションで重複した値を受け入れたくない場合は、__TreeSetを使った良い解決策があります。
まず、最初のマップに重複したエントリを追加しましょう。
Employee employee5 = new Employee(1L, "Mher");
map.put(employee5.getName(), employee5);
Employee employee6 = new Employee(22L, "Annie");
map.put(employee6.getName(), employee6);
4.1. キー順で並べ替え
キーエントリでマップをソートするには
SortedSet<String> keySet = new TreeSet<>(map.keySet());
keySet
を印刷して出力を確認しましょう。
----[Annie, George, John, Mher]----
これで、マップキーが重複せずにソートされました。
4.2. 値で並べ替え
同様に、マップ値の場合、変換コードは次のようになります。
SortedSet<Employee> values = new TreeSet<>(map.values());
そして結果は次のとおりです。
----[Employee{id=1, name='Mher'},
Employee{id=2, name='George'},
Employee{id=8, name='John'},
Employee{id=22, name='Annie'}]----
ご覧のとおり、出力に重複はありません。 ** これは
equals
と__hashCodeをオーバーライドするときにカスタムオブジェクトで動作します。
5ラムダとストリームの使用
-
Java 8以降、ストリームAPIとラムダ式を使用してマップをソートできます** 。必要なのは、マップの
stream
パイプラインで
sorted__メソッドを呼び出すだけです。
5.1. キー順で並べ替え
キーでソートするには、
__ comparingByKey
__comparatorを使います。
map.entrySet()
.stream()
.sorted(Map.Entry.<String, Employee>comparingByKey())
.forEach(System.out::println);
最後の
forEach
ステージは結果を出力します。
Annie=Employee{id=22, name='Annie'}
George=Employee{id=2, name='George'}
John=Employee{id=8, name='John'}
Mher=Employee{id=1, name='Mher'}
デフォルトでは、ソートモードは昇順です。
5.2. 値で並べ替え
もちろん、
Employee
オブジェクトによってもソートできます。
map.entrySet()
.stream()
.sorted(Map.Entry.comparingByValue())
.forEach(System.out::println);
ご覧のとおり、上記のコードは
Employee
オブジェクトの
id
フィールドでソートされたマップを出力します。
Mher=Employee{id=1, name='Mher'}
George=Employee{id=2, name='George'}
John=Employee{id=8, name='John'}
Annie=Employee{id=22, name='Annie'}
さらに、結果を新しいマップにまとめることができます。
Map<String, Employee> result = map.entrySet()
.stream()
.sorted(Map.Entry.comparingByValue())
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(oldValue, newValue) -> oldValue, LinkedHashMap::new));
-
デフォルトでは、
Collectors.toMap
は新しいHashMapを返しますが、**
HashMap
は繰り返しを保証するものではありません。
6. Guava
を使う
最後に、
HashMap
のソートを可能にするライブラリはGuavaです。始める前に、https://www.baeldung.com/guava-maps[maps in Guava]についての記事を確認すると便利です。
まず、地図を
従業員の
Id
フィールドで並べ替えたいので、https://www.baeldung.com/guava-ordering[
Ordering__]を宣言しましょう。
Ordering naturalOrdering = Ordering.natural()
.onResultOf(Functions.forMap(map, null));
さて、必要なのは
__ImmutableSortedMap
__を使って結果を説明することだけです。
ImmutableSortedMap.copyOf(map, naturalOrdering);
繰り返しますが、出力は
id
フィールドで並べられたマップです。
Mher=Employee{id=1, name='Mher'}
George=Employee{id=2, name='George'}
John=Employee{id=8, name='John'}
Annie=Employee{id=22, name='Annie'}
7. 概要
この記事では、
__HashMapを
__byキーまたは値でソートする方法をいくつか紹介しました。
そして、
Comparable
を実装することで、属性がカスタムクラスの場合にこれを実行する方法を詳しく調べました。
最後に、いつものように、ディスカッション中に使用されたコードはhttps://github.com/eugenp/tutorials/tree/master/java-collections-maps[GitHubについて]にあります。