Рубрики
Без рубрики

Как отсортировать хэш-карту по ключу в Java

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

Автор оригинала: David Landup.

В этом уроке мы рассмотрим как сортировать хэш-карту по ключу в Java .

Давайте продолжим и создадим простую Хэш-карту :

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

У нас есть Строка s в качестве ключей и Целое число s в качестве значений. В большинстве случаев вы будете сталкиваться с Целым числом s или Строкой s в качестве ключей и пользовательскими объектами, Строкой s или Целым числом s в качестве значений. Мы хотим отсортировать эту Хэш-карту на основе ключей String .

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

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

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

Сортировка хэш-карты по ключу с помощью карты деревьев

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

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

Создать древовидную карту с учетом Хэш-карты так же просто , как предоставить вызову конструктора несортированную карту:

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

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

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

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

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

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

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

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

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

Действительно приятная особенность заключается в том, что мы можем предоставить новый компаратор() для Карты деревьев и указать в нем нашу собственную логику сравнения. Например, давайте посмотрим, как мы можем сортировать ключи строк по длине в хэш-карте , используя длину строк и пользовательский компаратор:

Map sortedMap = new TreeMap<>(new Comparator() {
    @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);

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

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

Затем, как только мы определили критерии сортировки для Карты деревьев , мы использовали метод putAll() для вставки всех элементов из Несортированной карты в Отсортированную карту .

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

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

Карта теперь сортируется с помощью пользовательского Компаратора , который в этом случае сравнивает длину с Строк ключей. Вы можете использовать любую логику здесь, чтобы удовлетворить ваши конкретные потребности.

Сортировка хэш-карты по ключу с помощью LinkedHashMap

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

Итак, самый простой способ преобразовать несортированную Хэш-карту в связанную хэш-карту – это добавить элементы в том порядке, в котором мы хотели бы их видеть.

Сортировка Ключей хэш-карты Лексикографически

Git Essentials

Ознакомьтесь с этим практическим руководством по изучению Git, содержащим лучшие практики и принятые в отрасли стандарты. Прекратите гуглить команды Git и на самом деле изучите это!

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

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

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

То, что мы здесь сделали, – это потоковое | Несортированное изображение набор объектов Map.Entry . Затем, используя метод sorted () , мы предоставили удобный Компаратор , созданный comparingByKey () , который сравнивает данные объекты с их реализацией сравнения по умолчанию.

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

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

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

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

Сортировка ключей хэш-карты с помощью пользовательского компаратора

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

Map 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 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 по ключу . Первоначально мы использовали древовидную карту для сортировки и поддержания порядка отсортированных записей, как с использованием компаратора по умолчанию, так и пользовательского.

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