Home > Mobile >  Creating generic comparator for List<List<Comparable>>
Creating generic comparator for List<List<Comparable>>

Time:12-31

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);
}
  • Related