1. Введение
В этом кратком руководстве мы узнаем, как сортировать HashMap
в Java .
В частности, мы рассмотрим сортировку записей HashMap
по их ключу или значению, используя:
ДеревоКарта
ArrayList
иCollections.sort()
Набор деревьев
- Использование
потокового
API - Использование библиотеки
гуавы
2. Использование древовидной карты
Как мы знаем, ключи в TreeMap
сортируются в их естественном порядке . Это хорошее решение, когда мы хотим отсортировать пары ключ-значение по их ключу. Итак, идея состоит в том, чтобы передать все данные из нашего HashMap
в TreeMap
.
Для начала давайте определим HashMap
и инициализируем его некоторыми данными:
Map<String, Employee> 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
мы реализовали Comparable
:
public class Employee implements Comparable<Employee> {
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<String, Employee> sorted = new TreeMap<>(map);
Мы также можем использовать метод putAll
для копирования данных:
TreeMap<String, Employee> 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
. Ключевое отличие от предыдущего метода заключается в том, что здесь мы не поддерживаем интерфейс карты
.
3.1. Сортировать по ключу
Давайте загрузим набор ключей в ArrayList
:
List<String> employeeByKey = new ArrayList<>(map.keySet());
Collections.sort(employeeByKey);
И вывод:
[Annie, George, John, Mher]
3.2. Сортировать по значению
А что, если мы хотим отсортировать значения карты по полю id объекта
Employee
? Мы также можем использовать ArrayList
для этого.
Во-первых, давайте скопируем значения в список:
List<Employee> employeeById = new ArrayList<>(map.values());
Затем сортируем:
Collections.sort(employeeById);
Помните, что это работает, потому что Employee
реализует интерфейс Comparable
. В противном случае нам нужно было бы определить ручной компаратор для нашего вызова 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.
Во-первых, давайте добавим несколько повторяющихся записей на нашу исходную карту:
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<String> keySet = new TreeSet<>(map.keySet());
Давайте напечатаем keySet
и посмотрим на результат:
[Annie, George, John, Mher]
Теперь у нас есть ключи карт, отсортированные без дубликатов.
4.2. Сортировать по значению
Аналогично, для значений карты код преобразования выглядит так:
SortedSet<Employee> 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'}]
Как мы видим, в выводе нет дубликатов. Это работает с пользовательскими объектами, когда мы переопределяем equals
и hashCode.
5. Использование лямбда-выражений и потоков
Начиная с Java 8, мы можем использовать Stream API и лямбда-выражения для сортировки карты . Все, что нам нужно, это вызвать метод sorted в потоковом
конвейере
карты.
5.1. Сортировать по ключу
Для сортировки по ключу мы используем компаратор CompareByKey
:
map.entrySet()
.stream()
.sorted(Map.Entry.<String, Employee>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);
Как мы видим, приведенный выше код выводит карту, отсортированную по полям id объектов
Employee
:
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<String, Employee> result = map.entrySet()
.stream()
.sorted(Map.Entry.comparingByValue())
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(oldValue, newValue) -> oldValue, LinkedHashMap::new));
Обратите внимание, что мы собрали наши результаты в LinkedHashMap
. По умолчанию Collectors.toMap
возвращает новый HashMap, но, как мы знаем, HashMap
не гарантирует порядок итераций , в
отличие от
LinkedHashMap .
6. Использование гуавы
Наконец, библиотека, которая позволяет нам сортировать HashMap
, — это Guava. Прежде чем мы начнем, будет полезно проверить нашу статью о картах в Guava .
Во-первых, давайте объявим 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
, когда атрибут является пользовательским классом.
Наконец, как всегда, код, использованный в этой статье, можно найти на GitHub .