Сортируем хэш-карту по значению в Java

В этом уроке мы рассмотрим, как сортировать хэш-карту по значению в Java.

Создадим простую хэш-карту:

Map<String, Integer> unsortedMap = new HashMap();

unsortedMap.put("John", 21);
unsortedMap.put("Maria", 34);
unsortedMap.put("Mark", 31);
unsortedMap.put("Sydney", 24);

unsortedMap.entrySet().forEach(System.out::println);

Строки выступают в качестве ключей, а целые числа в качестве значений. Мы хотели бы отсортировать эту карту на основе значений.

Хэш-карты в любом случае не гарантируют сохранение порядка элементов. Порядок может меняться, и вы получите следующее:

John=21
Mark=31
Maria=34
Sydney=24

Если вы повторно запустите эту программу, она сохранит этот порядок, так как хэш-карты упорядочивают свои элементы в ячейки на основе хэш-значения ключей. При печати значений из хэш-карты её содержимое выйдет последовательно, поэтому результаты останутся прежними, если мы повторно запустим программу несколько раз.

Сортируем хэш-карты по значению с помощью LinkedHashMap

LinkedHashMap сохраняет порядок вставки. Он хранит двусвязный список всех записей, позволяя вам получать доступ к его элементам и перебирать их.

Итак, самый простой способ преобразовать несортированную хэш-карту в связанную хэш-карту – это добавить элементы в том порядке, в котором мы хотели бы, чтобы они были.

Сортируем хэш-карты в порядке возрастания

Чтобы отсортировать несортированную карту, которую мы видели ранее, мы создадим новую связанную хэш-карту для размещения элементов в том порядке, в котором мы хотим.

Начнём с сортировки хэш-карты в порядке возрастания:

Map<String, Integer> sortedMap = unsortedMap.entrySet().stream()
        .sorted(Comparator.comparingInt(e -> e.getValue()))
        .collect(Collectors.toMap(
                Map.Entry::getKey,
                Map.Entry::getValue,
                (a, b) -> { throw new AssertionError(); },
                LinkedHashMap::new
        ));

sortedMap.entrySet().forEach(System.out::println);

Мы выполнили потоковую передачу набора объектов Map.Entry несортированной карте. Теперь, с помощью метода sorted(), мы можем использовать различные компараторы, чтобы указать, как сравниваются записи.

Поскольку мы имеем дело с простыми целыми числами, мы можем легко использовать метод Comparator.comparingint() и передать лямбда-выражение. С помощью этого выражения мы предоставляем ключ сортировки из типа T (в нашем случае целое число). Затем этот метод возвращает компаратор, который сравнивает этот ключ сортировки.

Как только они будут отсортированы, мы можем собрать их в новую карту с помощью вызова Collectors.toMap(), где мы используем те же Map.Entry::getKey и Map.Entry::GetValue, что и в несортированной карте.

Наконец, создаётся новый экземпляр LinkedHashMap, в который вставляются все эти элементы в отсортированном порядке.

Результат выполнения кода:

John=21
Sydney=24
Mark=31
Maria=34

Вместо Comparator.comparingint(), вы можете использовать Map.Entry.comparingbyvalue():

Map<String, Integer> sortedMap = unsortedMap.entrySet().stream()
        .sorted(Map.Entry.comparingByValue())
        .collect(Collectors.toMap(
                Map.Entry::getKey,
                Map.Entry::getValue,
                (a, b) -> { throw new AssertionError(); },
                LinkedHashMap::new
        ));

sortedMap.entrySet().forEach(System.out::println);

Однако при таком подходе вы не можете указать свою собственную логику для сравнений. Сопоставимые значения, такие как целые числа, сортируются с помощью скрытой реализации. Однако вы можете указать пользовательский объект и указать свою собственную логику сравнения в этом классе.

Вы также можете просто использовать Map.Entry::getValue:

Map<String, Integer> sortedMap = unsortedMap.entrySet().stream()
        .sorted(Comparator.comparingInt(Map.Entry::getValue))
        .collect(Collectors.toMap(
                Map.Entry::getKey,
                Map.Entry::getValue,
                (a, b) -> { throw new AssertionError(); },
                LinkedHashMap::new
        ));

sortedMap.entrySet().forEach(System.out::println);

Вот, что мы получим:

John=21
Sydney=24
Mark=31
Maria=34

Этот вариант функционально точно такой же, как и предыдущий, так как Map.Entry.comparingbyvalue() использует метод GetValue() для сравнения записей.

Сортируем хэш-карты в порядке убывания

Теперь давайте отсортируем хэш-карту в порядке убывания. В этот раз мы будем использовать метод -e.GetValue():

Map<String, Integer> sortedMap = unsortedMap.entrySet().stream()
        .sorted(Comparator.comparingInt(e -> -e.getValue()))
        .collect(Collectors.toMap(
                Map.Entry::getKey,
                Map.Entry::getValue,
                (a, b) -> { throw new AssertionError(); },
                LinkedHashMap::new
        ));

sortedMap.entrySet().forEach(System.out::println);

Результат:

Maria=34
Mark=31
Sydney=24
John=21

Используя этот метод, вы можете легко переключаться между порядком убывания и возрастания.

Заключение

В этом уроке мы рассмотрели, как сортировать хэш-карту Java. Для этого мы использовали потоки Java 8 с классом LinkedHashMap.

Ответить