Monday, September 12, 2011

Java: Sorting objects by multiple attributes

The best way to do this is by using the ComparatorChain from the Apache Collections Framework.
You have to implement for every attribute a Comparator that you add to the Chain in the order you need. Now you can use the chain like a normal Comparator.
Here is how it looks like in code:
 package org.test.comparator;  
 public class Person {  
      public Person(String name, int age) {  
           this.name = name;  
           this.age = age;  
      }  
      public String name;  
      public Integer age;  
      @Override  
      public String toString() {  
           return "[" + name + "|" + age + "]";  
      }  
 }  

 package org.test.comparator;  
   
 import java.util.ArrayList;  
 import java.util.Collections;  
 import java.util.Comparator;  
 import java.util.List;  
   
 import org.apache.commons.collections.comparators.ComparatorChain;  
   
 public class TestComparatorChain {  
      public static void main(String[] args) {  
           List<Person> persons = new ArrayList<Person>();  
           persons.add(new Person("stan", 31));  
           persons.add(new Person("kyle", 22));  
           persons.add(new Person("stan", 11));  
           persons.add(new Person("kyle", 30));  
             
           Comparator<Person> comparatorName = new Comparator<Person>() {  
                @Override  
                public int compare(Person o1, Person o2) {  
                     return o1.name.compareToIgnoreCase(o2.name);  
                }  
           };  
             
           Comparator<Person> comparatorAge = new Comparator<Person>() {  
                @Override  
                public int compare(Person o1, Person o2) {  
                     return o1.age.compareTo(o2.age);  
                }  
           };  
             
           ComparatorChain chain = new ComparatorChain();  
           chain.addComparator(comparatorName);  
           chain.addComparator(comparatorAge);  
             
           System.out.println(persons);  
             
           Collections.sort(persons, chain);  
             
           System.out.println(persons);  
      }  
 }  

Resulting two lines:
[[stan|31], [kyle|22], [stan|11], [kyle|30]]
[[kyle|22], [kyle|30], [stan|11], [stan|31]]

The commons-collections-3.2.1.jar is with 575 kb quite big if you only want to use one class of it. Fortunately the class ComparatorChain has no dependencys to other classes of the collections library.
Download it from here and copy it into you project but keep the original package name org.apache.commons.collections.comparators, it helps you later to track back where the class came from.

3 comments:

  1. Thank you for this. The direct link to the class is dead, so here it is: http://www.jarvana.com/jarvana/view/commons-collections/commons-collections/3.2.1/commons-collections-3.2.1-sources.jar!/org/apache/commons/collections/comparators/ComparatorChain.java

    Thank you again, I upvoted you on SO for this too!

    ReplyDelete
  2. Thanks a lot, it is really helpful. My project already include commons-collection, so need not have to download source seperate.

    ReplyDelete