Как отсортировать 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); У нас есть строки как ключи и целые числа как значения. В большинстве случаев вы будете встречать целые числа или строки в качестве ключей, а также настраиваемые объекты, строки или целые числа.

В этом руководстве мы рассмотрим, как отсортировать 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 качестве значений. В большинстве случаев вы встретите Integer или String качестве ключей и настраиваемые объекты String или Integer качестве значений. Нам нужно отсортировать эту HashMap на основе ключей String

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

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

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

Сортировка HashMap по ключу с помощью TreeMap

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

Сортировка строковых ключей лексикографически

Создать TreeMap учетом HashMap так же просто, как предоставить вызов конструктора с несортированной картой:

 Map<String, Integer> sortedMap = new TreeMap<>(unsortedMap); 
 sortedMap.entrySet().forEach(System.out::println); 

Выполнение этого кода приводит к:

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

Поскольку мы не предоставили никакого компаратора, срабатывает компаратор по умолчанию, используемый для Strings. В частности, когда вы сравниваете Strings, метод compareTo() сравнивает лексикографическое значение каждой String и сортирует их в порядке возрастания.

Мы увидим имена, начинающиеся с A , перед именами, начинающимися с B и т. Д. Давайте добавим два новых имени и посмотрим, что произойдет:

 unsortedMap.put("Adam", 35); 
 unsortedMap.put("Aaron", 22); 
 
 Map<String, Integer> sortedMap = new TreeMap<>(unsortedMap); 
 sortedMap.entrySet().forEach(System.out::println); 

Это приводит к:

 Aaron=22 
 Adam=35 
 John=21 
 Maria=34 
 Mark=31 
 Sydney=24 

Сортировка ключей с помощью настраиваемого компаратора

Действительно приятной особенностью является то, что мы можем предоставить new Comparator<T>() для TreeMap и указать в нем нашу собственную логику сравнения. Например, давайте посмотрим, как мы можем отсортировать строковые ключи по длине в HashMap , используя length строк и настраиваемый компаратор:

 Map<String, Integer> sortedMap = new TreeMap<>(new Comparator<String>() { 
 @Override 
 public int compare(String o1, String o2) { 
 int lengthDifference = o1.length() - o2.length(); 
 if (lengthDifference != 0) return lengthDifference; 
 return o1.compareTo(o2); 
 } 
 }); 
 
 sortedMap.putAll(unsortedMap); 
 
 sortedMap.entrySet().forEach(System.out::println); 

Здесь мы TreeMap с настраиваемым Comparator а в переопределенном compare() мы указали желаемую логику.

Поскольку у нас нет гарантии, что o1.length() - o2.length() не будет равно 0, простой оператор if гарантирует, что мы сравниваем их лексикографически, если их длина одинакова.

Затем, когда мы определили критерии сортировки для TreeMap , мы использовали putAll() метод , чтобы вставить все элементы из unsortedMap минуты sortedMap .

Выполнение этого кода приводит к:

 Adam=35 
 John=21 
 Mark=31 
 Aaron=22 
 Maria=34 
 Sydney=24 

Карта теперь сортируется с помощью специального Comparator , который в этом случае сравнивает length s ключей String Здесь вы можете использовать любую логику для удовлетворения ваших конкретных потребностей.

Сортировка HashMap по ключу с LinkedHashMap

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

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

Сортировка ключей HashMap лексикографически

Теперь давайте unsortedMap , создав новый LinkedHashMap который будет содержать элементы в отсортированном порядке.

У Map.Entry есть очень удобный метод, который здесь вступает в игру - comparingByKey() , который сравнивает ключи, если у них есть допустимые методы сравнения. Поскольку мы имеем дело со String s, это метод compareTo() , который снова отсортирует String s лексикографически:

 Map<String, Integer> sortedMap = unsortedMap.entrySet().stream() 
 .sorted(Map.Entry.comparingByKey()) 
 .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 созданный с помощью comparingByKey() , который сравнивает данные объекты с их реализацией сравнения по умолчанию.

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

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

Выполнение этого кода приводит к:

 Aaron=22 
 Adam=35 
 John=21 
 Maria=34 
 Mark=31 
 Sydney=24 

Сортировка ключей HashMap с помощью настраиваемого компаратора

В качестве альтернативы вы можете использовать свой собственный Comparator вместо того, который сгенерирован Map.Entry.comparingByKey() . Это так же просто, как предоставить Comparator.comparing() и передать ему действительное лямбда-выражение :

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

Здесь мы воссоздали наш настраиваемый компаратор, который сортирует ключи по их значению из предыдущих разделов. Теперь String будут отсортированы по их длине, а не по их лексикографическому значению:

 Adam=35 
 John=21 
 Mark=31 
 Aaron=22 
 Maria=34 
 Sydney=24 

Конечно, вы можете легко переключиться с восходящего на нисходящий порядок, просто добавив - перед e.getKey().length() :

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

Это приводит к:

 Sydney=24 
 Aaron=22 
 Maria=34 
 Adam=35 
 John=21 
 Mark=31 

Кроме того, вы можете использовать другие компараторы, такие как Comparator.comparingInt() если вы имеете дело с целочисленными значениями (хотя мы здесь, общий компаратор также работает), Comparator.comparingDouble() или Comparator.comparingLong() чтобы удовлетворить твои нужды.

Заключение

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

Затем у нас есть потоки Java 8 с LinkedHashMap для достижения этой функции, как для стандартных, так и для настраиваемых компараторов в порядке возрастания и убывания.

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