Сортировка коллекций Java()
Сегодня мы рассмотрим метод сортировки коллекций Java. При работе с коллекциями в java нам чаще всего приходится сортировать данные.
Сортировка коллекций Java()
Класс Java Collections предоставляет нам очень удобный метод Collections.sort() для сортировки всего ArrayList. Существует два перегруженных метода Collections.sort() :
- sort(List list) : сортирует элементы списка в порядке возрастания их естественного порядка.
- sort(List list, Comparator c) : сортирует элементы списка в соответствии с порядком, заданным компаратором.
Обратите внимание, что в приведенных выше сигнатурах методов используются дженерики, но я удалил их здесь для простоты чтения. Давайте один за другим рассмотрим, как и когда мы можем использовать оба этих метода.
Сортировка коллекций Java (список списка)
Рассмотрим ArrayList из String :
List fruits = new ArrayList(); fruits.add("Apple"); fruits.add("Orange"); fruits.add("Banana"); fruits.add("Grape");
Теперь мы отсортируем его с помощью Collections.sort() :
Collections.sort(fruits); // Print the sorted list System.out.println(fruits);
Вывод этой программы будет:
[Apple, Banana, Grape, Orange]
Следовательно, мы видим, что Collections.sort() отсортировал список строк в лексическом порядке. И ничего не возвращает. Что, если у нас есть список пользовательских объектов? Конечно, мы можем и их отсортировать. Рассмотрим класс Fruit:
package com.journaldev.collections; public class Fruit < private int id; private String name; private String taste; Fruit(int id, String name, String taste)< this.id=id; this.name=name; this.taste=taste; >>
Создадим список фруктов:
List fruitList=new ArrayList(); Fruit apple=new Fruit(1, "Apple", "Sweet"); Fruit orange=new Fruit(2, "Orange", "Sour"); Fruit banana=new Fruit(4, "Banana", "Sweet"); Fruit grape=new Fruit(3, "Grape", "Sweet and Sour"); fruitList.add(apple); fruitList.add(orange); fruitList.add(banana); fruitList.add(grape);
package com.journaldev.collections; public class Fruit implements Comparable < private int id; private String name; private String taste; Fruit(int id, String name, String taste)< this.id=id; this.name=name; this.taste=taste; >@Override public int compareTo(Object o) < Fruit f = (Fruit) o; return this.id - f.id ; >>
Теперь, когда мы внедрили Comparable , мы можем отсортировать список без ошибок:
Collections.sort(fruitList); fruitList.forEach(fruit -> < System.out.println(fruit.getId() + " " + fruit.getName() + " " + fruit.getTaste()); >);
Вывод будет следующим:
1 Apple Sweet 2 Orange Sour 3 Grape Sweet and Sour 4 Banana Sweet
Сортировка коллекций Java (список, компаратор c)
Чтобы определить пользовательскую логику сортировки, отличную от естественного порядка элементов, мы можем реализовать интерфейс java.util.Comparator и передать его экземпляр в качестве второго аргумента сортировать() . Предположим, что мы хотим определить порядок на основе поля \name Fruit. Мы реализуем Comparator , и в его методе compare() нам нужно написать логику для сравнения:
package com.journaldev.collections; class SortByName implements Comparator < @Override public int compare(Fruit a, Fruit b) < return a.getName().compareTo(b.getName()); >>
Теперь мы можем отсортировать его с помощью этого компаратора:
Collections.sort(fruitList, new SortByName());
Вывод будет следующим:
1 Apple Sweet 4 Banana Sweet 3 Grape Sweet and Sour 2 Orange Sour
Вместо того, чтобы писать новый класс для Comparator, используя лямбда-функцию, мы также можем обеспечить логику сортировки во время выполнения:
Collections.sort(fruitList, (a, b) -> < return a.getName().compareTo(b.getName()); >);
Java Collections.reverseOrder
По умолчанию Collection.sort выполняет сортировку в порядке возрастания. Если мы хотим отсортировать элементы в обратном порядке, мы можем использовать следующие методы:
- reverseOrder() : возвращает Comparator , который устанавливает обратное естественному порядку элементов коллекции.
- reverseOrder(Comparator cmp) : возвращает Comparator , который устанавливает обратный порядок указанного компаратора.
Вот примеры для обоих этих методов:
Пример Java Collections reverseOrder()
Collections.sort(fruits, Collections.reverseOrder()); System.out.println(fruits);
Он выведет фрукты в обратном алфавитном порядке:
[Orange, Grape, Banana, Apple]
Пример Java Collections reverseOrder (Comparator cmp)
Collections.sort(fruitList, Collections.reverseOrder(new SortByName())); fruitList.forEach(fruit -> < System.out.println(fruit.getId() + " " + fruit.getName() + " " + fruit.getTaste()); >);
2 Orange Sour 3 Grape Sweet and Sour 4 Banana Sweet 1 Apple Sweet
Это все, что касается метода sort() для коллекций Java и его примеров. Ссылка: документ API
Все права защищены. © Linux-Console.net • 2019-2023
Как отсортировать коллекцию java
Ниже приведены несколько способов сортировки коллекций :
import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; public class App public static void main(String[ ] args) ListInteger> list = new ArrayList<>(List.of(5, 3, 2, 1, 4)); Collections.sort(list); System.out.println(list); // => [1, 2, 3, 4, 5] list.sort(Comparator.reverseOrder()); System.out.println(list); // => [5, 4, 3, 2, 1] list = list.stream() .sorted() .collect(Collectors.toList()); System.out.println(list); // => [1, 2, 3, 4, 5] > >
Сортировка списков в Java
Для возможности сортировки объектов в коллекциях наследниках List в Java существует статический метод класса java.util.Collections .
Это значит вы можете сортировать элементы таких классов как ArrayList, LinkedList, CopyOnWriteArrayList и других классов, имплементирующих интерфейс List .
В общем виде, если у вас есть список из строк:
[z, b, c, a, k, z]
то после сортировки получите в списке порядок:
[a, b, c, k, z, z]
Простое использование метода sort() #
Если у нас в списке находятся объекты классов, которые известно как сравнить, то достаточно просто вызвать метод sort() и передать туда список. Таким образом в списке элементы поменяют порядок и будут отсортированы в порядке возрастания
//создание списка на основе массива var stringList = Arrays.asList("z", "b", "c", "a", "k", "z"); System.out.println(stringList); //сортировка списка в порядке возрастания Collections.sort(stringList); System.out.println(stringList);
Вывод в консоль:
[z, b, c, a, k, z] [a, b, c, k, z, z]
Так мы можем сортировать множество стандартных классов, таких как String, Integer, Double, Character и множество других.
Если более точно выразиться, то без дополнительных параметров возможно отсортировать список из любых элементов, классы которых имплементируют интерфейс сравнения Comparable .
Сортировка в обратном порядке #
Если мы хотим сортировать элементы в обратном порядке. То для этого передадим дополнительный аргумент в метод сортировки:
//создание списка на основе массива var stringList = Arrays.asList("z", "b", "c", "a", "k", "z"); System.out.println(stringList); //сортировка списка в обратном направлении Collections.sort(stringList, Collections.reverseOrder()); System.out.println(stringList);
[z, b, c, a, k, z] [z, z, k, c, b, a]
Добавляем возможность сортировки своих классов #
Если стандартные классы уже готовы к сортировке, то если мы напишем свой класс, то Java не знает как есть сравнивать с объектами этого же класса.
Чтобы научить сравнивать объекты есть два варианта:
- создать класс на основе Comparator и там прописать правила сравнения в методе int compare(T o1, T o2) . Полученный объект из класса использовать всегда, когда нам надо сортировать объекты. Такой вариант отлично подходит, когда нам надо сортировать объекты по разным правилам и можем использовать нужный нам класс Comparator.
- добавить в класс (являющимся, элементом списка) имплементацию интерфейса Comparable и прописать правила сравнения в методе int compareTo(T o) . Тогда не потребуется указывать каждый раз компаратор, данное правило сравнение будет по-умолчанию для этого объекта.
Оба метода возвращают целое число, которое обычно интерпретируется так:
- число больше 0 -> объект с которым сравнивают больше текущего
- число равно 0 -> объекты одинаковые
- число меньше 0 -> объект с которым сравнивают меньше текущего
Создадим свой класс, например для студента:
class Student private final String name; private final double avgMark; public Student(String name, double avgMark) this.name = name; this.avgMark = avgMark; > @Override public String toString() return " + name + '\'' + ", m=" + avgMark + '>'; > >
Класс специально минимально простой: все параметры задаются в конструкторе, и используются значения только для печати данных при вызове toString, что поможет нам в визуализации результата.
Для начала, посмотрим, что будет если мы попробуем отсортировать список из студентов:
var ivan = new Student("Иван", 4.3); var olga = new Student("Ольга", 3.8); var eugene = new Student("Женя", 4.9); var studentList = Arrays.asList(ivan, olga, eugene); System.out.println(studentList); //сортировка списка Collections.sort(studentList); System.out.println(studentList);
Такой код не скомпилируется, так как метод sort() не просто ожидает список, но еще важно, чтобы элемент списка был наследником Comparable:
public static T extends Comparable super T>> void sort(ListT> list) list.sort(null); >
Использование Comparable #
Для создания возможности сортировки, нам необходимо научить сравнить объекты с другими такого-же типа. И такая реализация будет использоваться по-умолчанию при сравнении объектов одного класса.
Имплементируем Comparable интерфейс, и реализуем метод compareTo:
class Student implements ComparableStudent> private final String name; private final double avgMark; public Student(String name, double avgMark) this.name = name; this.avgMark = avgMark; > @Override public String toString() return " + name + '\'' + ", m=" + avgMark + '>'; > @Override public int compareTo(Student o) return name.compareTo(o.name); > >
Обратите внимание, внутри метод мы решили сравнить две строки, а так как у String есть реализация Comparable — мы можем ее использовать.
В данном коде опущены части, с проверкой на null объектов o и полей класса.
Давайте проверим, как это будет работать:
var ivan = new Student("Иван", 4.3); var olga = new Student("Ольга", 3.8); var eugene = new Student("Женя", 4.9); var studentList = Arrays.asList(ivan, olga, eugene); System.out.println(studentList); //сортировка списка Collections.sort(studentList); System.out.println(studentList);
Все отлично, список отсортирован по полю name .
Вы можете делать более сложные условия сравнения, только не забывайте учитывать требование для успешной сортировки — два объекта, сколько бы мы их не сравнивали — должны всегда давать одинаковый результат.
Использование Comparator #
А что если нам надо сортировать студентов не по имени, а по средней оценке? И при этом оставить возможность сортировать по имени, которое должна использоваться по умолчанию для создания различных документов.
Нам на помощь придет отдельный класс Comparator , которые хранит в себе логику сравнения объектов и при сортировке, мы можем использовать нужное правило, то есть нужный объект класса Comparator .
Для начала добавим в класс Student геттеры, так как нам уже необходимо использовать данные класса в классе компаратора.
class Student implements ComparableStudent> private final String name; private final double avgMark; public Student(String name, double avgMark) this.name = name; this.avgMark = avgMark; > @Override public String toString() return " + name + '\'' + ", m=" + avgMark + '>'; > @Override public int compareTo(Student o) return name.compareTo(o.name); > public String getName() return name; > public double getAvgMark() return avgMark; > >
и теперь создадим класс Comparator , тип для сравнения Student :
class ComparatorByAvgMark implements ComparatorStudent> @Override public int compare(Student o1, Student o2) return Double.compare(o1.getAvgMark(), o2.getAvgMark()); > >
Мы снова использовали готовый метод для сравнения стандартного класса Double , это помогает не выдумывать свои реализации, а использовать уже существующие.
Также снова опущены проверки на null объектов o1, o2.
Теперь можно использовать данный класс, и в этот раз нам пригодится перегруженный метод Collections.sort() , который принимает компаратор:
var ivan = new Student("Иван", 4.3); var olga = new Student("Ольга", 3.8); var eugene = new Student("Женя", 4.9); var studentList = Arrays.asList(ivan, olga, eugene); System.out.println(studentList); //сортировка списка c использованием компаратора Collections.sort(studentList, new ComparatorByAvgMark()); System.out.println(studentList);
И мы видим — сортировка по возрастанию средней оценки студента.
Хорошо, давайте сделаем обратную сортировку, высокие оценки должны быть в начале списка. Для этого нам потребуется изменить поведение компаратора, и для этого у компаратора есть метод reversed() :
Collections.sort(studentList, new ComparatorByAvgMark().reversed());
и в итоге получим нужный результат:
Но это еще не все что может компаратор, можно создавать цепочки. Например, сначала сортируем по оценкам, а если оценки одинаковые, то по имени.
Это можно реализовать не создавая отдельного класса, а воспользоваться функцией:
Collections.sort(studentList, new ComparatorByAvgMark().reversed() .thenComparing(Student::getName));
При такой сортировки, оценки будут в порядке убывания, а внутри одной средней оценки, студенты будут по имени в порядке возрастания.
Метод sort() у самого списка #
Кроме использования метода Collections.sort() , можно вызывать похожий метод у самого списка List.sort() . Метод принимает один аргумент — компаратор.
На примере списка студентов:
studentList.sort(new ComparatorByAvgMark());
Как отсортировать коллекцию без использования вспомогательных коллекций по пяти условиям
Логика следующая из не отсортированной коллекции, по каждому условию добавляются в определенную коллекцию, затем каждая коллекция сортируется по году и добавляется в конечную. Код полностью рабочий но можно ли как то сделать это без помощи вспомогательных коллекций, к примеру использую компаратор, если да то как?
Отслеживать
задан 17 ноя 2019 в 17:55
Alexandar Vysotskiy Alexandar Vysotskiy
71 1 1 серебряный знак 5 5 бронзовых знаков
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
Ваше количество кода просто убивает. Ваш код полностью рабочий, только работает он некорректно. По году у вас сортировка не производится, хотя в стримах вы вызываете метод compareTo для каждой коллекции (ваш метод compareTo всегда возвращает 0, что означает равность переменных в любом случае, сортировка не происходит). И почему вы не типизируете интерфейс Comparable, когда имплементируете его, разве вы не видите, что он с дженериком? По этой причине в метод compareTo вам прилетает object вместо желаемого для сортировки CarForSort. Мало того, в 4-ой коллекции вы сравниваете moles3 с цветом. Исходя из того, что вы добавляете в коллекцию, moles3 — не цвет, а модель. Ваше условие никогда не срабатывает и поэтому 4-ая коллекция всегда будет пустой. Если это исправит и переписать с компаратором, то выглядит это примерно так (метод compareTo можно еще отрефакторить, но просто нет времени):
import java.util.ArrayList; import java.util.List; public class Sort < public static void main(String[] args) < final ListnotSort = new ArrayList<>(); notSort.add(new CarForSort("orange", "coupe", "bmw", "3", 1992)); notSort.add(new CarForSort("black", "cabriolet", "bmw", "6", 2008)); notSort.add(new CarForSort("black", "hatchback", "opel", "astra", 2000)); notSort.add(new CarForSort("red", "suv", "mercedes", "ml", 1992)); notSort.add(new CarForSort("blue", "sedan", "kia", "rio", 2008)); notSort.add(new CarForSort("gray", "sedan", "tesla", "moles3", 2019)); notSort.add(new CarForSort("red", "sedan", "tesla", "model_s", 2019)); notSort.add(new CarForSort("green", "sedan", "bmw", "5", 1993)); notSort.add(new CarForSort("orange", "sedan", "bmw", "7", 1994)); notSort.add(new CarForSort("blue", "coupe", "bmw", "6", 2001)); notSort.add(new CarForSort("red", "sedan", "bmw", "3", 1998)); notSort.add(new CarForSort("orange", "sedan", "bmw", "7", 1997)); notSort.add(new CarForSort("blue", "sedan", "opel", "omega", 2000)); notSort.add(new CarForSort("orange", "white", "opel", "vectra", 1999)); notSort.add(new CarForSort("black", "coupe", "kia", "stinger", 2019)); notSort.add(new CarForSort("orange", "sedan", "bmw", "7", 2017)); notSort.add(new CarForSort("orange", "coupe", "bmw", "3", 1992)); notSort.add(new CarForSort("orange", "coupe", "bmw", "6", 2014)); notSort.add(new CarForSort("orange", "coupe", "astra", "4", 1998)); notSort.stream().sorted().forEach(System.out::println); > > import java.util.function.Supplier; public class CarForSort implements Comparable < private final String color; private final String bodyStyle; private final String make; private final String model; private final Integer year; public CarForSort(String color, String bodyStyle, String make, String model, int year) < this.color = color; this.bodyStyle = bodyStyle; this.make = make; this.model = model; this.year = year; >public String getColor() < return color; >public String getBodyStyle() < return bodyStyle; >public String getMake() < return make; >public String getModel() < return model; >public Integer getYear() < return year; >@Override public String toString() < return make + " " + model + " " + color + " " + bodyStyle + " " + year; >@Override public int compareTo(CarForSort car) < int comp1 = pairComparing(this, ()->this.getColor(), car, ()->car.getColor(), "bmw", "orange"); if (comp1 != 0) return comp1; comp1 = pairComparing(this, ()->this.getColor(), car, ()->car.getColor(), "opel", "black"); if (comp1 != 0) return comp1; comp1 = pairComparing(this, ()->this.getBodyStyle(), car, ()->car.getBodyStyle(), "opel", "sedan"); if (comp1 != 0) return comp1; comp1 = pairComparing(this, ()->this.getModel(), car, ()->car.getModel(), "tesla", "moles3"); if (comp1 != 0) return comp1; return this.year-car.getYear(); > private int pairComparing (CarForSort car1, Supplier getter1, CarForSort car2, Supplier getter2, String make, String param) < int car1Comp=0, car2Comp=0; if (car1.getMake().equals(make) && getter1.get().equals(param)) car1Comp=1; if (car2.getMake().equals(make) && getter2.get().equals(param)) car2Comp=1; if (car1Comp==1 && car2Comp==1) return car1.getYear()-car2.getYear(); return car2Comp-car1Comp; >>
