Сортировать HashMap в Java

Сортировать HashMap в Java

1. Вступление

В этом кратком руководстве мы узнаем, какsort a HashMap in Java.

В частности, мы рассмотрим сортировку записейHashMap по их ключу или значению, используя:

  • TreeMap

  • ArrayList иCollections.sort()

  • TreeSet

  • ИспользуяStream API, и, наконец,

  • Используя списокGuava 

2. ИспользуяTreeMap

Как известно,keys in TreeMap are sorted using their natural order. Это хорошее решение, когда мы хотим отсортировать пары ключ-значение по их ключу. Идея состоит в том, чтобы поместить все данные изHashMap вTreeMap.

Для начала давайте определимHashMap и инициализируем его некоторыми данными:

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

Для классаEmployeenote that we’ve implemented Comparable:

public class Employee implements Comparable {

    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 by, используя его конструктор:

TreeMap sorted = new TreeMap<>(map);

Или методputAll для копирования данных:

TreeMap 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. Ключевое отличие от предыдущего метода в том, чтоwe don’t maintain the Map interface here.

3.1. Сортировать по ключу

Загрузим набор ключей вArrayList:

List employeeByKey = new ArrayList<>(map.keySet());
Collections.sort(employeeByKey);

И вывод:

[Annie, George, John, Mher]

3.2. Сортировать по значению

А что, если мы хотим отсортировать значения карты по полюid объектаEmployee? Мы также можем использовать для этогоArrayList.

Сначала скопируем значения в список:

List employeeById = new ArrayList<>(map.values());

И после этого мы сортируем это:

Collections.sort(employeeById);

Помните, что это работает, потому чтоEmployee implements the Comparable interface. В противном случае нам нужно было бы определить ручной компаратор для нашего вызова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 

Если мыdon’t want to accept duplicate values in our sorted collection, there is a nice solution with 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 keySet = new TreeSet<>(map.keySet());

НапечатаемkeySet и посмотрим на результат:

[Annie, George, John, Mher]

Теперь у нас есть ключи карты, отсортированные без дубликатов.

4.2. Сортировать по значению

Аналогично, для значений карты код преобразования выглядит следующим образом:

SortedSet 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'}]

Как мы видим, в выходных данных нет дубликатов. This works with custom objects when we override equals and hashCode.с

5. Использование лямбда-выражений и потоков

Since the Java 8, we can use the Stream API and lambda expressions to sort the map. Все, что нам нужно, это вызвать методsorted над спайплайномstream карты.

5.1. Сортировать по ключу

Для сортировки по ключу мы используем scomparatorcomparingByKey :

map.entrySet()
  .stream()
  .sorted(Map.Entry.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 result = map.entrySet()
  .stream()
  .sorted(Map.Entry.comparingByValue())
  .collect(Collectors.toMap(
    Map.Entry::getKey,
    Map.Entry::getValue,
    (oldValue, newValue) -> oldValue, LinkedHashMap::new));

Note that we collected our results into a LinkedHashMap. По умолчаниюCollectors.toMap возвращает новую HashMap, но, как мы знаем,HashMap doesn’t guarantee iterationorder,, аLinkedHashMap -.

6. Использование гуавы

Наконец, библиотека, которая позволяет нам сортироватьHashMap, - это Guava. Прежде чем мы начнем, будет полезно проверить нашу статью оmaps in Guava.

Во-первых, давайте объявимOrdering, поскольку мы хотим отсортировать нашу карту по полюEmployee’sId:

Ordering naturalOrdering = Ordering.natural()
  .onResultOf(Functions.forMap(map, null));

Теперь все, что нам нужно, это использоватьImmutableSortedMap to для иллюстрации результатов:

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 by или по значению.

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

Наконец, как всегда, код, использованный во время обсуждения, можно найтиover on GitHub.