1. 序章

このクイックチュートリアルでは、JavaでHashMapをソートする方法を学習します。

具体的には、 HashMap エントリを、次のコマンドを使用してキーまたは値で並べ替えることを検討します。

  • TreeMap
  • ArrayListおよびCollections.sort()
  • TreeSet
  • StreamAPIの使用
  • Guavaライブラリの使用

2. TreeMapを使用する

ご存知のとおり、TreeMapのキーは、自然な順序を使用して並べ替えられます。 これは、キーと値のペアをキーで並べ替える場合に適したソリューションです。 したがって、アイデアは、すべてのデータをHashMapから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に格納します。

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を使用してマップのエントリを並べ替えることができます。 以前の方法との主な違いは、ここではマップインターフェイスを維持しないことです。

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以降、StreamAPIとラムダ式を使用してマップを並べ替えることができます。 必要なのは、マップのストリームパイプライン上でsortedメソッドを呼び出すことだけです。

5.1. キーで並べ替え

キーで並べ替えるには、compareByKeyコンパレータを使用します。

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));

結果をLinkedHashMapに収集したことに注意してください。デフォルトでは、 Collectors.toMap は新しいHashMapを返しますが、ご存知のとおり、HashMapは反復を保証しません order LinkedHashMapはそうです。

6. グアバの使用

最後に、HashMapをソートできるライブラリはGuavaです。 始める前に、Guavaマップに関する記事を確認すると便利です。

まず、従業員の Id フィールドでマップを並べ替えたいので、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をキーまたは値で並べ替えるいくつかの方法を確認しました。

また、属性がカスタムクラスの場合に、Compareableを実装することでこれを行う方法を学びました。

最後に、いつものように、この記事で使用されているコードは、GitHubにあります。