7

I'm trying to sort the list in descending order using Comparator Interface. But the values are not sorted in descending order. Not sure what i'm doing wrong here.

public class Student {

    int rollNo;
    String name;
    int age;
    
    public Student(int RollNo, String Name, int Age){
        this.rollNo = RollNo;
        this.name = Name;
        this.age = Age;
    }
}

public class AgeComparator implements Comparator<Student>{

    @Override
    public int compare(Student o1, Student o2) {
        return o1.age > o2.age ? 1 :(o1.age < o2.age ? -1 : 0); //Ascending
         
        //return o1.age < o2.age ? -1 :(o1.age > o2.age ? 1 : 0); // Descending
    }

}

public class Comparator_Sort {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        
        ArrayList<Student> al = new ArrayList<Student>();
        al.add(new Student(5978, "Vishnu", 50));
        al.add(new Student(5979, "Vasanth", 30));
        al.add(new Student(5980, "Santhosh", 40));
        al.add(new Student(5981, "Santhosh", 20));
        al.add(new Student(5982, "Santhosh", 10));
        al.add(new Student(5983, "Santhosh", 5));
        
        
        Collections.sort(al, new AgeComparator());
        
        for(Student s : al){
            System.out.println(s.rollNo+" "+s.name+" "+s.age);
        }
    }
}

I can be able to sort the list in ascending order, whereas i'm unable to do it for descending order

return o1.age > o2.age ? 1 :(o1.age < o2.age ? -1 : 0); //Sorted in Ascending
return o1.age < o2.age ? -1 :(o1.age > o2.age ? 1 : 0); // Not sorted in Descending

Comparator documentation -- Returns: a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second. The source is found from here

Can anyone tell me why the sorting for descending is not working?

0

7 Answers 7

13

Your two ternary conditional operators produce the same result (since you swapped both > with < and -1 with 1):

return o1.age > o2.age ? 1 :(o1.age < o2.age ? -1 : 0); //Sorted in Ascending
return o1.age < o2.age ? -1 :(o1.age > o2.age ? 1 : 0); // Not sorted in Descending

For descending order you need :

return o1.age > o2.age ? -1 :(o1.age < o2.age ? 1 : 0);
Sign up to request clarification or add additional context in comments.

5 Comments

If u check the source i have provided, it follows the below criteria
I'm following the same approach, but descending order sorting is not working
@Aishu -1 : o1 < o2 0 : o1 == o2 +1 : o1 > o2 produces ascending order. If you want descending order, you need to reverse the roles of o1 and o2.
Got little confused from the source stackoverflow.com/questions/6478515/…
@Aishu As I said, that question (or rather the accepted answer) describe the logic for getting ascending order. compare should return a negative value if o1 should come before o2. For ascending order that also means that o1<o2. For descending order, the opposite is true - you return a negative value if o1>o2.
10

@Eran already pointed out the error in your comparator.

I'd like to add that you may just return o1.age - o2.age. The result of comparison does not have to be exactly -1 or 1 for < or > it may be just negative or positive.

And you could have also called Comparator.reversed. Or Comparator.comparing(Student::getAge).reversed().

Comments

2

The age value is an integer, and it seems that it is always positive, you can use this shorten code.

return o1.age - o2.age; // Ascending
return o2.age - o1.age; // Descending

This code cannot be used for negative values.

For example,

if o1.age = 10, o2.age = 11, this code will return -1 for ascending and 1 for descending, that is correct.

But the case o1.age = -10, o2.age = -11, this code will return 1 for ascending and -1 for descending, that is incorrect.

Comments

1

Abusing ternary conditions is error-prone because not readable.

Why not simply write classic if-else-if for the descending comparator ?

public class AgeComparatorDesc implements Comparator<Student> {

  @Override
  public int compare(Student o1, Student o2) {
    if (o1.age > o2.age) {
        return -1;
    } else if (o1.age < o2.age) {
        return 1;
    }    
     return 0;
  }

}

Comments

1

You can directly use a comparator class instance. Below is the code example.

Assuming the you define a getter method "getAge()" for student.

Comparator<Student> m_studentComparator = new Comparator<Sudent>() {
        @Override
        public int compare(Student lhs, Student rhs) {
            return rhs.getAge().compareTo(lhs.getAge());  // Descending order
        }
    };

Collections.sort(<<Your list>> , m_studentComparator);   // this would return the descending order list.

If you want an Ascending order list, just change the return statement in the overridden method to

return lhs.getAge().compareTo(rjs.getAge());    // Ascending order.

Hope this answers your question.

3 Comments

age needs to be of class Integer and not to be defined as the primitive type int
@Davide One could do that. That helps in handling null cases for age. Thanks !
Sure, I just wanted to emphasize this aspect
0

Well you should either write it as:

return o1.age < o2.age ? 1 :(o1.age > o2.age ? -1 : 0); 

or write it as:

return o1.age > o2.age ? -1 :(o1.age < o2.age ? 1 : 0); 

Your current attempt will still sort it in ascending order.

Comments

0
return o1.age > o2.age ? -1 :(o1.age < o2.age ? 1 : 0);

though for descending simply just multiply your ascending return statement with -1. like this

-1*(return o1.age > o2.age ? 1 :(o1.age < o2.age ? -1 : 0))

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.