Home > database >  Wrong order during sorting at first by predefined order, and then by natural order using Comparator
Wrong order during sorting at first by predefined order, and then by natural order using Comparator

Time:11-08

I have a simple object class:

public class Employee {
    String name;
    String secondName;
 // Conctructor, getters & setters
}

List of employees:

        List<Employee> employees = new ArrayList<>(Arrays.asList(
                new Employee("Jake",  "Bbb"),
                new Employee("Ann",   "Aaa"),
                new Employee("Ivy",   "Bbb"),
                new Employee("Ivy",   "Aaa"),
                new Employee("Jake",  "Aaa"),
                new Employee("Tom",   "Iii"),
                new Employee("Neil",  "Xxx"),
                new Employee("Keith", "Ooo"),
                new Employee("Tom",   "Rrr")
        ));

I want to sort them in predefined order of secondNames first and than in natural order of names:

List<String> definedOrder = Arrays.asList("Iii", "Bbb", "Aaa");

in such way:

employees.sort(
        Comparator.comparing((Employee e) -> definedOrder.indexOf(e.getSecondName()))
                .thenComparing(Employee::getName));

for (Employee em : employees){
     System.out.println(em.getSecondName()   " / "   em.getName());
}

And I experct to recive the predifined objects in the list first, then the rest objects:

Iii / Tom
Bbb / Ivy
Bbb / Jake
Aaa / Ann
Aaa / Ivy
Aaa / Jake
Ooo / Keith
Xxx / Neil
Rrr / Tom

But I receive objects firstly sorted in the natural order by names, (using thenComparing() method), and then from predefined comparison by secondNames:

Ooo / Keith
Xxx / Neil
Rrr / Tom
Iii / Tom
Bbb / Ivy
Bbb / Jake
Aaa / Ann
Aaa / Ivy
Aaa / Jake

CodePudding user response:

You're missing that definedOrder.indexOf(e.getSecondName()) returns -1 when second name is not found in definedOrder.

That's why Ooo, Xxx and Rrr appear before Iii, Bbb, and Aaa.

And, as Ooo, Xxx and Rrr all share the same value (-1) for the purposes of comparing, they are sorted by thenComparing(Employee::getName)) among themselves.


To fix this behavior, you can check if definedOrder.indexOf(e.getSecondName()) returns -1 and, if so, return Integer.MAX_VALUE instead.

  • Related