I'm trying to create a generic comparator for a List<List<Comparable>>
which can sort on multiple fields. The structure represents a List of rows and within each row, I want to sort on multiple columns.
I have this
public static void sort(List<List<Comparable>> data, int... sortColumns) {
System.out.println("Sorting on columns " Arrays.toString(sortColumns));
Comparator<List<Comparable>> comparator = null;
for (int i : sortColumns) {
final Comparator<List<Comparable>> listComparator = (o1, o2) -> o1.get(i).compareTo(o2.get(i));
if (comparator == null) {
comparator = listComparator;
} else {
comparator.thenComparing(listComparator) ;
}
}
data.sort(comparator);
}
But it only seems to work on the first sort field, not multiple fields.
For example, this is correctly sorted on column 0, but not column 1
[[4, foo], [5, baz], [5, barf], [1, zed], [6, fizz], [2, baz], [1, baz]]
Sorting on columns [0, 1]
[[1, zed], [1, baz], [2, baz], [4, foo], [5, baz], [5, barf], [6, fizz]]
Here again, it correctly sorts on column 1, but not column 0
[[4, foo], [5, baz], [5, barf], [1, zed], [6, fizz], [2, baz], [1, baz]]
Sorting on columns [1, 0]
[[5, barf], [5, baz], [2, baz], [1, baz], [6, fizz], [4, foo], [1, zed]]
Am I doing something wrong in constructing the comparator? Particularly, the use of thenComparing
Update
The problem is that thenComparing
doesn't change the existing comparator but returns a new one. I changed the line in the else to comparator = comparator.thenComparing(listComparator);
and it worked
CodePudding user response:
And as @dan1st has pointed out in the comments, you're not storing the result generated by the invocation of Comparator.thenComparing()
.
Also, note Comparable
interface is generic, and you're using a Comparable of row type in your method.
Your method can be reimplemented in the following way:
public static <T extends Comparable<T>> void
sort(List<List<T>> data, int... sortColumns) {
Comparator<List<T>> comparator = Arrays.stream(sortColumns)
.mapToObj(i -> Comparator.<List<T>, T>comparing(list -> list.get(i)))
.reduce(Comparator::thenComparing)
.orElseThrow();
data.sort(comparator);
}