JavaでHashMapをソートする

JavaでHashMapを並べ替える

1. 前書き

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

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

  • ツリーマップ

  • ArrayListおよびCollections.sort()

  • ツリーセット

  • Stream API,を使用し、最後に

  • Guava libraryの使用

2. TreeMapの使用

ご存知のように、keys in TreeMap are sorted using their natural order。 これは、キーでキーと値のペアをソートする場合に適したソリューションです。 したがって、アイデアは、すべてのデータをHashMapからTreeMapにプッシュすることです。

手始めに、HashMapを定義し、いくつかのデータで初期化します。

Map 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クラスの場合、note that we’ve implemented Comparable:

public class Employee implements Comparable {

    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 sorted = new TreeMap<>(map);

または、データをコピーするためのputAllメソッド:

TreeMap 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を使用して、マップのエントリを並べ替えることができます。 前の方法との主な違いは、we don’t maintain the Map interface hereです。

3.1. キーで並べ替え

キーセットをArrayListにロードしましょう:

List employeeByKey = new ArrayList<>(map.keySet());
Collections.sort(employeeByKey);

そして出力は次のとおりです。

[Annie, George, John, Mher]

3.2. 値で並べ替え

ここで、マップ値をEmployeeオブジェクトのidフィールドで並べ替える場合はどうでしょうか。 そのためにArrayListを使用することもできます。

まず、値をリストにコピーしましょう。

List employeeById = new ArrayList<>(map.values());

そしてその後、ソートします:

Collections.sort(employeeById);

Employee implements the Comparable interfaceであるため、これが機能することを忘れないでください。 それ以外の場合は、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 を使用する

don’t want to accept duplicate values in our sorted collection, there is a nice solution with 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 keySet = new TreeSet<>(map.keySet());

keySetを出力して、出力を見てみましょう。

[Annie, George, John, Mher]

これで、重複することなくマップキーがソートされました。

4.2. 値で並べ替え

同様に、マップ値の場合、変換コードは次のようになります。

SortedSet 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'}]

ご覧のとおり、出力に重複はありません。 This works with custom objects when we override equals and hashCode.

5. ラムダとストリームの使用

Since the Java 8, we can use the Stream API and lambda expressions to sort the map。 必要なのは、マップのstream pipelineに対してsortedメソッドを呼び出すことだけです。

5.1. キーで並べ替え

キーで並べ替えるには、comparingByKey comparatorを使用します。

map.entrySet()
  .stream()
  .sorted(Map.Entry.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 result = map.entrySet()
  .stream()
  .sorted(Map.Entry.comparingByValue())
  .collect(Collectors.toMap(
    Map.Entry::getKey,
    Map.Entry::getValue,
    (oldValue, newValue) -> oldValue, LinkedHashMap::new));

Note that we collected our results into a LinkedHashMap.デフォルトでは、Collectors.toMapは新しいHashMapを返しますが、ご存知のとおり、HashMap doesn’t guarantee iterationorder,LinkedHashMapを返します。

6. グアバの使用

最後に、HashMapをソートできるライブラリはGuavaです。 始める前に、maps in Guavaについての記事を確認すると便利です。

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

また、Comparableを実装することで、属性がカスタムクラスの場合にこれを行う方法を詳しく調べました。

最後に、いつものように、ディスカッション中に使用されたコードはover on GitHubで見つけることができます。