Sorting using Comparator- Descending order (User defined classes)

Java

Java Problem Overview


I want to sort my objects in descending order using comparator.

class Person {
 private int age;
}

Here I want to sort a array of Person objects.

How can I do this?

Java Solutions


Solution 1 - Java

You can do the descending sort of a user-defined class this way overriding the compare() method,

Collections.sort(unsortedList,new Comparator<Person>() {
    @Override
    public int compare(Person a, Person b) {
        return b.getName().compareTo(a.getName());
    }
});

Or by using Collection.reverse() to sort descending as user Prince mentioned in his comment.

And you can do the ascending sort like this,

Collections.sort(unsortedList,new Comparator<Person>() {
    @Override
    public int compare(Person a, Person b) {
        return a.getName().compareTo(b.getName());
    }
});

Replace the above code with a Lambda expression(Java 8 onwards) we get concise:

Collections.sort(personList, (Person a, Person b) -> b.getName().compareTo(a.getName()));

As of Java 8, List has sort() method which takes Comparator as parameter(more concise) :

personList.sort((a,b)->b.getName().compareTo(a.getName()));

Here a and b are inferred as Person type by lambda expression.

Solution 2 - Java

For whats its worth here is my standard answer. The only thing new here is that is uses the Collections.reverseOrder(). Plus it puts all suggestions into one example:

/*
**  Use the Collections API to sort a List for you.
**
**  When your class has a "natural" sort order you can implement
**  the Comparable interface.
**
**  You can use an alternate sort order when you implement
**  a Comparator for your class.
*/
import java.util.*;

public class Person implements Comparable<Person>
{
	String name;
	int age;

	public Person(String name, int age)
	{
	   	this.name = name;
	   	this.age = age;
	}

	public String getName()
	{
		return name;
	}

	public int getAge()
	{
		return age;
	}

	public String toString()
	{
		return name + " : " + age;
	}

	/*
	**  Implement the natural order for this class
	*/
	public int compareTo(Person p)
	{
		return getName().compareTo(p.getName());
	}

	static class AgeComparator implements Comparator<Person>
	{
		public int compare(Person p1, Person p2)
		{
			int age1 = p1.getAge();
			int age2 = p2.getAge();

			if (age1 == age2)
				return 0;
			else if (age1 > age2)
				return 1;
			else
				return -1;
		}
	}

	public static void main(String[] args)
	{
		List<Person> people = new ArrayList<Person>();
		people.add( new Person("Homer", 38) );
		people.add( new Person("Marge", 35) );
		people.add( new Person("Bart", 15) );
		people.add( new Person("Lisa", 13) );

		// Sort by natural order

		Collections.sort(people);
		System.out.println("Sort by Natural order");
		System.out.println("\t" + people);

		// Sort by reverse natural order

		Collections.sort(people, Collections.reverseOrder());
		System.out.println("Sort by reverse natural order");
		System.out.println("\t" + people);

		//  Use a Comparator to sort by age

		Collections.sort(people, new Person.AgeComparator());
		System.out.println("Sort using Age Comparator");
		System.out.println("\t" + people);

		//  Use a Comparator to sort by descending age

		Collections.sort(people,
			Collections.reverseOrder(new Person.AgeComparator()));
		System.out.println("Sort using Reverse Age Comparator");
		System.out.println("\t" + people);
	}
}

Solution 3 - Java

I would create a comparator for the person class that can be parametrized with a certain sorting behaviour. Here I can set the sorting order but it can be modified to allow sorting for other person attributes as well.

public class PersonComparator implements Comparator<Person> {

  public enum SortOrder {ASCENDING, DESCENDING}

  private SortOrder sortOrder;

  public PersonComparator(SortOrder sortOrder) {
    this.sortOrder = sortOrder;
  }

  @Override
  public int compare(Person person1, Person person2) {
    Integer age1 = person1.getAge();
    Integer age2 = person2.getAge();
    int compare = Math.signum(age1.compareTo(age2));

    if (sortOrder == ASCENDING) {
      return compare;
    } else {
      return compare * (-1);
    }
  }
}

(hope it compiles now, I have no IDE or JDK at hand, coded 'blind')

Edit

Thanks to Thomas, edited the code. I wouldn't say that the usage of Math.signum is good, performant, effective, but I'd like to keep it as a reminder, that the compareTo method can return any integer and multiplying by (-1) will fail if the implementation returns Integer.MIN_INTEGER... And I removed the setter because it's cheap enough to construct a new PersonComparator just when it's needed.

But I keep the boxing because it shows that I rely on an existing Comparable implementation. Could have done something like Comparable<Integer> age1 = new Integer(person1.getAge()); but that looked too ugly. The idea was to show a pattern which could easily be adapted to other Person attributes, like name, birthday as Date and so on.

Solution 4 - Java

String[] s = {"a", "x", "y"};
Arrays.sort(s, new Comparator<String>() {

	@Override
	public int compare(String o1, String o2) {
		return o2.compareTo(o1);
	}
});
System.out.println(Arrays.toString(s));

-> [y, x, a]

Now you have to implement the Comparator for your Person class. Something like (for ascending order): compare(Person a, Person b) = a.id < b.id ? -1 : (a.id == b.id) ? 0 : 1 or Integer.valueOf(a.id).compareTo(Integer.valueOf(b.id)).

To minimize confusion you should implement an ascending Comparator and convert it to a descending one with a wrapper (like this) new ReverseComparator<Person>(new PersonComparator()).

Solution 5 - Java

Using Google Collections:

class Person {
 private int age;

 public static Function<Person, Integer> GET_AGE =
  new Function<Person, Integer> {
   public Integer apply(Person p) { return p.age; }
  };

}

public static void main(String[] args) {
 ArrayList<Person> people;
 // Populate the list...

 Collections.sort(people, Ordering.natural().onResultOf(Person.GET_AGE).reverse());
}

Solution 6 - Java

The java.util.Collections class has a sort method that takes a list and a custom Comparator. You can define your own Comparator to sort your Person object however you like.

Solution 7 - Java

package com.test;

import java.util.Arrays;

public class Person implements Comparable {

private int age;

private Person(int age) {
	super();
	this.age = age;
}

public int getAge() {
	return age;
}

public void setAge(int age) {
	this.age = age;
}

@Override
public int compareTo(Object o) {
	Person other = (Person)o;
	if (this == other)
		return 0;
	if (this.age < other.age) return 1;
	else if (this.age == other.age) return 0;
	else return -1;
	
}

public static void main(String[] args) {
	
	Person[] arr = new Person[4];
	arr[0] = new Person(50);
	arr[1] = new Person(20);
	arr[2] = new Person(10);
	arr[3] = new Person(90);
	
	Arrays.sort(arr);
	
	for (int i=0; i < arr.length; i++ ) {
		System.out.println(arr[i].age);
	}
}

}

Here is one way of doing it.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionManojView Question on Stackoverflow
Solution 1 - JavaLuckyView Answer on Stackoverflow
Solution 2 - JavacamickrView Answer on Stackoverflow
Solution 3 - JavaAndreas DolkView Answer on Stackoverflow
Solution 4 - JavaThomas JungView Answer on Stackoverflow
Solution 5 - JavafinnwView Answer on Stackoverflow
Solution 6 - JavaRobert ChristieView Answer on Stackoverflow
Solution 7 - JavaShamikView Answer on Stackoverflow