11

This is my list:

Name: Ben     || Age: 5 || Group: 1
Name: Andy    || Age: 6 || Group: 2
Name: Charlie || Age: 6 || Group: 2
Name: Ben     || Age: 5 || Group: 1
Name: Andy    || Age: 5 || Group: 2
Name: Charlie || Age: 5 || Group: 1

I want to sort the list by Group, if Group is equal then by Age, and if Age is equal then by Name. But so far I can only sort by one attribute, using Lambda Expressions:

list.sort((Object o1, Object o2) -> o1.getGroup().compareTo(o2.getGroup()));

If I try

o1.getGroup().compareTo(o2.getGroup()) && o1.getAge().compareTo(o2.getAge())

it's turned out error...

2 Answers 2

19

Change lambda expression to lambda {block}, and you don't have to specify the parameter types:

list.sort((o1, o2) -> {
    int cmp = o1.getGroup().compareTo(o2.getGroup());
    if (cmp == 0)
        cmp = Integer.compare(o1.getAge(), o2.getAge());
    if (cmp == 0)
        cmp = o1.getName().compareTo(o2.getName());
    return cmp;
});
Sign up to request clarification or add additional context in comments.

4 Comments

You are the saviour of my day :) Thanks
@HuyVo The right way to thank somebody here is by upvoting their answers.
How to do this with raw arrays (not Lists)? This syntax does not seem to work when sorting an int[] arr with: Arrays.sort(arr, <multi-line lambda>);
@AnnaVopureta There are no sorting methods for sorting primitive arrays by custom order. The Java runtime library only has methods for sorting primitive arrays by their natural order. See: How to sort an array of ints using a custom comparator?
16

You can use the static method Comparator.comparing to create a comparator based on a function that returns a comparable value. Such a comparator can be chained with others.

Assuming your type is called Person, you would have:

Comparator<Person> c = Comparator
        .comparing(p -> p.getGroup())
        .thenComparing(p -> p.getAge())
        .thenComparing(p -> p.getName())

If any of the getters return a primitive type, you have to use - for example - comparingInt and thenComparingInt, respectively. You can also use method references:

Comparator<Person> c = Comparator
        .comparing(Person::getGroup)
        .thenComparing(Person::getAge)
        .thenComparing(Person::getName)

But ... if your class has a natural ordering according to these values, you better let it implement the interface Comparable and write the compare logic in there:

class Person implements Comparable<Person> {
    ...
    @Override
    public int compareTo(Person other) {
        int compare = Integer.compare(getGroup(), other.getGroup());
        if (compare == 0) {
            compare = Integer.compare(getAge(), other.getAge());
        }
        if (compare == 0) {
            compare = getName.compareTo(other.getName());
        }
        return compare;
    }
}

This code snippet can also be used in a lambda expression:

list.sort((o1, o2) -> {
    int compare = Integer.compare(o1.getGroup(), o2.getGroup());
    if (compare == 0) {
        compare = Integer.compare(o1.getAge(), o2.getAge());
    }
    if (compare == 0) {
        compare = o1.getName.compareTo(o2.getName());
    }
    return compare;
});

2 Comments

Use Integer.compare() instead of subtraction, to prevent bad results on very large values.
Your first example doesn’t work. The compiler has no chance to deduce that p is a Person

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.