Как отсортировать список по нескольким полям
Короткий ответ
thenComparing() добавляет следующее поле — оно сравнивается, только если предыдущие равны:
record Employee(String department, String name) {}
void main() {
var staff = new ArrayList<>(List.of(
new Employee("Sales", "Oleg"),
new Employee("IT", "Boris"),
new Employee("Sales", "Anna"),
new Employee("IT", "Anna")));
staff.sort(Comparator.comparing(Employee::department).thenComparing(Employee::name));
staff.forEach(e -> IO.println(e.department() + " " + e.name()));
}Результат:
IT Anna
IT Boris
Sales Anna
Sales OlegРазный порядок
Чтобы одно поле шло по убыванию, передайте в thenComparing() отдельный компаратор:
record Player(String team, int score) {}
void main() {
var players = new ArrayList<>(List.of(
new Player("Red", 10), new Player("Blue", 30), new Player("Red", 25)));
players.sort(Comparator.comparing(Player::team)
.thenComparing(Player::score, Comparator.reverseOrder()));
IO.println(players);
}Результат:
[Player[team=Blue, score=30], Player[team=Red, score=25], Player[team=Red, score=10]]Значения null
Comparator.nullsLast() ставит элементы с null в конец, а не падает с исключением:
record Task(String title, Integer priority) {}
void main() {
var tasks = new ArrayList<>(List.of(new Task("b", null), new Task("a", 2), new Task("c", 1)));
tasks.sort(Comparator.comparing(Task::priority, Comparator.nullsLast(Comparator.naturalOrder())));
IO.println(tasks);
}Результат:
[Task[title=c, priority=1], Task[title=a, priority=2], Task[title=b, priority=null]]Частая ошибка
Поставить reversed() в конец цепочки. Он разворачивает весь компаратор, а не только последнее поле:
record Player(String team, int score) {}
void main() {
var players = new ArrayList<>(List.of(
new Player("Red", 10), new Player("Blue", 30), new Player("Red", 25)));
players.sort(Comparator.comparing(Player::team).thenComparing(Player::score).reversed());
IO.println(players);
}Результат:
[Player[team=Red, score=25], Player[team=Red, score=10], Player[team=Blue, score=30]]Команды тоже отсортировались по убыванию. Указывайте порядок для конкретного поля, как в примере выше.
Функции из этого ответа
- Comparator.thenComparing() — Добавляет второй критерий сортировки — для объектов, равных по первому.
- Comparator.comparing() — Создаёт компаратор, который сравнивает объекты по одному полю.
- Comparator.reversed() — Возвращает компаратор с обратным порядком. Для естественного порядка есть Comparator.reverseOrder().