Научитесь сортировать Java Set, List и Map примитивных типов и пользовательских объектов с помощью Comparator, Comparable и новых лямбда-выражений. Мы также научимся сортировать в порядке возрастания и убывания.
//Сортировка массиваМассивы.сортировать( arrayOfItems );Массивы.сортировать( arrayOfItems, Коллекции.обратныйпорядок() );Массивы.сорт(arrayOfItems, 2, 6);Arrays.parallelSort(arrayOfItems);//Сортировка спискаКоллекции.сортировка(numbersList);Коллекции.сортировка(numbersList, Коллекции.обратныйпорядок());//Сортировка набораУстановить в список -> Сортировать -> Список для установкиКоллекции.сортировка(numbersList);//Сортировка картыTreeMap<Целое число, Строка> treeMap = new TreeMap<>(map);неотсортированнаяКарта.entrySet().транслировать().sorted(Карта.Entry.comparingByValue()).forEachOrdered(x -> sortedMap.put(x.getKey(), x.getValue()));//Java 8 ЛямбдаComparator<Сотрудник> nameSorter =(a, b) -> a.getName().compareToIgnoreCase(b.getName());Коллекции.сортировка(список, имяСортер);Коллекции.сортировка(список, Компаратор.сравнение(Сотрудник::getName));//Группировка по сортировкеКоллекции.сорт(список, Компаратор.сравнение(Сотрудник::getName).thenComparing(Сотрудник::getDob));
1. Сортировка списка объектов
Для сортировки списка объектов у нас есть два популярных подхода, то есть интерфейсы Comparable и Comparator. В следующих примерах мы отсортируем коллекцию объектов Employee разными способами.
public class Employee implements Comparable<Employee> {private Long id;private String name;private LocalDate dob;}
1.1. Сравнимый интерфейс
Интерфейс Comparable обеспечивает естественный порядок классов, которые его реализуют. Это делает классы сопоставимыми с другими его экземплярами.
Класс, реализующий интерфейс Comparable, должен переопределять метод compareTo(), в котором он может указать логику сравнения между двумя экземплярами одного и того же класса.
- Списки(и массивы) объектов, реализующих интерфейс Comparable, можно сортировать автоматически с помощью API Collections.sort() и Arrays.sort().
- Объекты, реализующие этот интерфейс, будут автоматически сортироваться при помещении в отсортированную карту(как ключи) или в отсортированный набор(как элементы).
- Настоятельно рекомендуется(хотя и не обязательно), чтобы естественные порядки соответствовали методу equals(). Практически все основные классы Java, реализующие Comparable, имеют естественные порядки, соответствующие equals().
ArrayList<Сотрудник> список = новый ArrayList<>();//добавляем сотрудников..Коллекции.сорт(список);
Чтобы отсортировать список в обратном порядке, лучше всего использовать API Comparator.reversed(), который устанавливает обратный порядок.
ArrayList<Сотрудник> список = новый ArrayList<>();//добавляем сотрудников..Коллекции.сортировка(список, Компаратор.перевернутый());
1.2 Интерфейс компаратора
Если естественный порядок не требуется, мы можем воспользоваться интерфейсом Comparator, чтобы применить пользовательское поведение сортировки.
Comparator не требует изменения исходного кода класса. Мы можем создать логику сравнения в отдельном классе, который реализует интерфейс Comparator и переопределить его метод compare().
Во время сортировки мы передаем экземпляр этого компаратора методу sort() вместе со списком пользовательских объектов.
Например, мы хотим отсортировать список сотрудников по имени, в то время как естественная сортировка реализована по полю id. Поэтому для сортировки по полю name мы должны написать пользовательскую логику сортировки с использованием интерфейса Comparator.
импорт java.util.Comparator;открытый класс NameSorter реализует Comparator<Employee>{@Переопределитьpublic int сравнить(Сотрудник e1, Сотрудник e2){вернуть e1.getName().compareToIgnoreCase( e2.getName() );}}
Обратите внимание на использование NameSorter в методе sort() в качестве второго аргумента в данном примере.
ArrayList<Employee> list = new ArrayList<>();//add employees to listCollections.sort(list, new NameSorter());
Чтобы выполнить обратную сортировку, нам просто нужно вызвать метод reversed() для экземпляра Comparator.
ArrayList<Employee> list = new ArrayList<>();//add employees to listCollections.sort(list, new NameSorter().reversed());
1.3 Сортировка с помощью лямбда-выражений
Лямбда-выражения помогают писать реализации Comparator на лету. Нам не нужно создавать отдельный класс для предоставления логики одноразового сравнения.
Comparator<Employee> nameSorter =(a, b) -> a.getName().compareToIgnoreCase(b.getName());Collections.sort(list, nameSorter);
1.4 Группировка по сортировке
Чтобы применить сортировку в стиле SQL к коллекции объектов по разным полям(группа по сортировке), мы можем использовать несколько компараторов в цепочке. Эту цепочку компараторов можно создать с помощью методов Comparator.comparing() и Comparator.thenComparing().
Например, мы можем отсортировать список сотрудников по имени, а затем снова отсортировать по возрасту.
ArrayList<Employee> list = new ArrayList<>();//add employees to listCollections.sort(list, Comparator.comparing(Employee::getName).thenComparing(Employee::getDob));
2. Сортировка массива
Используйте метод java.util.Arrays.sort() для сортировки заданного массива различными способами. Метод sort() — это перегруженный метод, который принимает все виды типов в качестве аргумента метода.
Этот метод реализует алгоритм сортировки Dual-Pivot Quicksort, который обеспечивает производительность O(n log(n)) для всех наборов данных и, как правило, быстрее традиционных реализаций Quicksort(с одной опорной точкой).
2.1. По возрастанию
Программа на Java для сортировки массива целых чисел по возрастанию с помощью метода Arrays.sort().
//Unsorted arrayInteger[] numbers = new Integer[] { 15, 11, ... };//Sort the arrayArrays.sort(numbers);
2.2. По убыванию
Java предоставляет компаратор Collections.reverseOrder() для изменения поведения сортировки по умолчанию в одной строке. Мы можем использовать этот компаратор для сортировки массива в порядке убывания.
Обратите внимание, что все элементы массива должны быть взаимно сопоставимы с помощью указанного компаратора.
//Unsorted arrayInteger[] numbers = new Integer[] { 15, 11, ... };//Sort the array in reverse orderArrays.sort(numbers, Collections.reverseOrder());
2.3 Сортировка диапазона массива
Метод Arrays.sort() является перегруженным методом и принимает два дополнительных параметра: fromIndex(включительно) и toIndex(исключительно).
При предоставлении вышеуказанных аргументов массив будет отсортирован в указанном диапазоне от позиции fromIndex до позиции toIndex.
Ниже приведен пример сортировки массива с элемента 9 по 18. То есть {9, 55, 47, 18} будут отсортированы, а остальные элементы не будут затронуты.
//Unsorted arrayInteger[] numbers = new Integer[] { 15, 11, 9, 55, 47, 18, 1123, 520, 366, 420 };//Sort the arrayArrays.sort(numbers, 2, 6);//Print array to confirmSystem.out.println(Arrays.toString(numbers));
Вывод программы.
[15, 11, 9, 18, 47, 55, 1123, 520, 366, 420]
2.4 Параллельная сортировка
Java 8 представила множество новых API для параллельной обработки наборов данных и потоков. Одним из таких API является Arrays.parallelSort().
Метод parallelSort() разбивает массив на несколько подмассивов, и каждый подмассив сортируется с помощью Arrays.sort() в разных потоках. Наконец, все отсортированные подмассивы объединяются в один отсортированный массив.
Вывод parallelSort() и sort(), оба API, наконец-то будут одинаковыми. Это просто вопрос использования параллелизма Java.
//Parallel sort complete arrayArrays.parallelSort(numbers);//Parallel sort array rangeArrays.parallelSort(numbers, 2, 6);//Parallel sort array in reverse orderArrays.parallelSort(numbers, Collections.reverseOrder());3. Сортировка набора
В Java нет прямой поддержки сортировки Set. Чтобы отсортировать Set, выполните следующие действия:
- Преобразовать набор в список.
- Сортировка списка с помощью API Collections.sort().
- Преобразовать список обратно в набор.
//Unsorted setHashSet<Integer> numbersSet = new LinkedHashSet<>(); //with Set itemsList<Integer> numbersList = new ArrayList<Integer>(numbersSet) ; //set -> list//Sort the listCollections.sort(numbersList);//sorted setnumbersSet = new LinkedHashSet<>(numbersList); //list -> set4. Сортировка карты
Карта — это коллекция пар ключ-значение. Поэтому логически мы можем сортировать карты двумя способами, то есть сортировать по ключу или сортировать по значению.
4.1 Сортировать по ключу
Лучшая и наиболее эффективная сортировка карты по ключам — это добавление всех записей карты в объект TreeMap. TreeMap всегда хранит ключи в отсортированном порядке.
HashMap<Integer, String> map = new HashMap<>(); //Unsorted MapTreeMap<Integer, String> treeMap = new TreeMap<>(map); //Sorted by map keys4.2 Сортировать по значению
В Java 8 класс Map.Entry имеет статический метод comparisonByValue(), который помогает нам сортировать Map по значениям.
Метод comparisonByValue() возвращает Comparator, который сравнивает Map.Entry в естественном порядке значений.
HashMap<Integer, String> unSortedMap = new HashMap<>(); //Unsorted Map//LinkedHashMap preserve the ordering of elements in which they are insertedLinkedHashMap<Integer, String> sortedMap = new LinkedHashMap<>();unSortedMap.entrySet().stream().sorted(Map.Entry.comparingByValue()).forEachOrdered(x -> sortedMap.put(x.getKey(), x.getValue()));5. Резюме
В приведенных выше примерах мы научились сортировать массив, список, карту и набор.
Мы увидели разные способы инициализации и использования интерфейса Comparator, включая лямбда-выражения. Мы также научились эффективно использовать интерфейс Comparator.