How to sort a list by multiple fields in different orders (asc/desc) in Java?

3.5k Views Asked by At

I have an ArrayList in Java and each element in the list is an object with 3 fields (a, b and c). I should order by a in ascending order; if 2 elements have the same value for a, they should be ordered by b in descending order; finally, if 2 elements have the same value even for b, they should be ordered by c in ascending order.

I tried other solutions posted on stackoverflow that are based on Comparator, but I did not get to order in descending order.

Could anyone kindly help me? Many thanks!

2

There are 2 best solutions below

0
Anonymous On BEST ANSWER

Comparator.reversed() for descending order

    Comparator<Element> compar = Comparator.comparing(Element::getA)
            .thenComparing(Comparator.comparing(Element::getB).reversed())
            .thenComparing(Element::getC);
    yourArrayList.sort(compar);

In addition to the reversed method I am exploiting the fact that thenComparing() is overloaded: one thenComparing() takes a Comparator as argument, which we need for reversing, the other just takes a method reference (or lambda) as argument (a Function in the declaration of thenComparing()).

If either a, b or c is a primitive int, long or double remember to use comparingInt(), comparingLong(), comparingDouble(), thenComparingInt(), etc.

0
Patrick On

Your Comparator for b needs to return a negative value if comparing o1 to o2 (where o1 is the first argument and o2 is the second), and o1.b is greater than o2.b. A Comparator returns negative when the first argument is comparably smaller (before) the second. As you want elements with greater b values to be interpreted as comparably smaller, reverse the return types from a typical ascending order Integer compare.

  class Obj {
    int a;
    int b;
    int c;

    Obj(int a, int b, int c) {
      this.a = a;
      this.b = b;
      this.c = c;
    }

    @Override
    public String toString() {
      return "{a: " + a + ", b: " + b + ", c: " + c + "}";
    }
  }

  public void sortObjs() {
    ArrayList<Obj> list = new ArrayList<>();

    list.add(new Obj(0, 1, 2));
    list.add(new Obj(0, 2, 2));
    list.add(new Obj(1, 1, 2));
    list.add(new Obj(1, 1, 1));

    list.sort((o1, o2) -> {
      if (o1.a != o2.a) {
        return o1.a - o2.a;
      }
      //if Objects' a fields are equal but b is not, sort by b in descending order
      if (o1.b != o2.b) {
        return o2.b - o1.b;
      }
      return o1.c - o2.c;
    });

    System.out.println(list);

  }

  public static void main(String[] args) {
    new Main().sortObjs();
  }
}

Output:

[{a: 0, b: 2, c: 2}, {a: 0, b: 1, c: 2}, {a: 1, b: 1, c: 1}, {a: 1, b: 1, c: 2}]