Как отсортировать HashMap по значению в Java

В этом руководстве мы рассмотрим, как отсортировать HashMap по значению в Java. Давайте продолжим и создадим простую HashMap: Map<String, Integer> unsortedMap = новая HashMap (); unsortedMap.put (&quot;Джон&quot;, 21); unsortedMap.put («Мария», 34); unsortedMap.put («Отметка», 31); unsortedMap.put (&quot;Сидней&quot;, 24); unsortedMap.entrySet (). forEach (System.out :: println); У нас есть строки как ключи и целые числа как значения. И мы хотели бы отсортировать эту карту по значениям. HashMaps не гарантирует поддержание порядка

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

Давайте продолжим и создадим простую HashMap :

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

У нас есть String качестве ключей и Integer качестве значений. И мы хотели бы отсортировать эту карту по значениям.

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

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

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

Примечание. TreeMap расширяет SortedMap , в отличие от реализации HashMap TreeMap s предназначены для отсортированного аналога, однако, TreeMap S только сортировать по ключам, учитывая компаратор.

Сортировка HashMap по значению с помощью LinkedHashMap

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

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

Сортировка HashMap в порядке возрастания

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

Начнем с сортировки HashMap в порядке возрастания:

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

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

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

После того, как они сортируются, мы можем collect() их в новую карту, через Collectors.toMap() вызова, где мы используем тот же Map.Entry::getKey и Map.Entry::getValue , как в unsortedMap .

Наконец, создается новый 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() для сравнения записей.

Сортировка HashMap в порядке убывания

Теперь давайте отсортируем несортированный HashMap в порядке убывания. Единственное отличие, которое вам нужно сделать, - это лямбда-выражение, которое мы предоставили Comparator.comparingInt() - вместо этого мы просто используем -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 

Это дополнительное преимущество использования этого подхода вместо Map.Entry.comparingByValue() или Map.Entry::getValue . Вы можете легко переключаться между порядком убывания и возрастания.

Заключение

В этом руководстве мы рассмотрели, как отсортировать Java HashMap по значению . Мы использовали Java 8 Streams с LinkedHashMap для достижения этой функциональности, как для сортировки по возрастанию, так и по убыванию значений.

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus