Сортируем хэш-карту по значению в 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.