Is it possible to sort objects by two fields both in reversed natural order using a Comparator.comparingInt chain

Rotzlucky :

Lets say I want to sort objects in an ArrayList on a field height in reversed order and if two values are the same I want to further sort on the field width also in reversed order. Is there a way by using something like

 Comparator<Test> comparator = Comparator
            .comparingInt((Test t) -> t.height).reversed()
            .thenComparingInt((Test t ) -> t.width).reversed();

I know I could use something like:

Collections.sort(list, new Comparator<Test>() {

        public int compare(Test o1, Test o2) {

            Integer x1 =  o1.height;
            Integer x2 =  o2.height;
            int sComp = x2.compareTo(x1);

            if (sComp != 0) {
                return sComp;
            }

            x1 = o1.width;
            x2 = o2.width;
            return x2.compareTo(x1);
        }});

But I'm really curious if there is one line solution

So regarding this mini-example

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class Main {

    public static void main(String[] args) {
        Test one = new Test();
        one.height = 2;
        one.width = 1;
        Test two = new Test();
        two.height = 2;
        two.width = 3;
        Test three = new Test();
        three.height = 1;
        three.width = 1;

        Comparator<Test> comparator = Comparator
            .comparingInt((Test t) -> t.height).reversed()
            .thenComparingInt((Test t ) -> t.width).reversed();

        List<Test> list = new ArrayList<>();
        list.add(one);
        list.add(two);
        list.add(three);

        list.stream()
            .sorted(comparator)
            .forEach(e -> System.out.println(e.height + "/" + e.width));
    }
}

class Test {
    int width;
    int height;
}

I get the output:

1/1
2/3
2/1

because the second reversed() reverses the whole list. Is there a way to gean a output of:

2/3
2/1
1/1
Ousmane D. :

just remove reversed() from comparingInt and only call reversed upon thenComparingLong:

Comparator<Test> comparator = 
      Comparator.comparingInt((Test t) -> t.height) // <--- removed reverse from this comparator
                .thenComparingLong((Test t ) -> t.width).reversed();

Further, given that width is an int I'd use thenComparingInt instead of thenComparingLong.

In addition, in regard to your stream pipeline, I'd suggest using forEachOrdered since you care about the order in which the elements are printed.

forEach is documented as:

The behavior of this operation is explicitly nondeterministic. For parallel stream pipelines, this operation does not guarantee to respect the encounter order of the stream, as doing so would sacrifice the benefit of parallelism.

Therefore:

 list.stream()
     .sorted(comparator)
     .forEachOrdered(e -> System.out.println(e.height + "/" + e.width));

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=73517&siteId=1