Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Как отсортировать список по нескольким полям

Короткий ответ

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().

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.