Multi Column Sorting in Java

Feb 21st, 2008 | By | Category: java

 

Link to code.

Java provides a reasonable API for sorting. The Collections.sort() static method which has been modelled from C++ STL caters to a decent cross-section of sorting requirements. This accepts a list of objects and sorts them.

To summarize what is provided by the sorting API in java, there are two variants of the sort static method of the Collections class.

Collections.sort(List list);

This will mutate the list and make it sorted. The items in the list are assumed to implement the java.lang.Comparable interface. Hence the items would have the ability to specify the order for the sort. For example let us take the following class

  1. public class Account implements Comparable{
  2.   private String accountNumber;
  3.   private double balance;
  4.   // Getters and setters.
  5.   public int compareTo(Object other) {
  6.     // return 0  or +ve number or negative number
  7.     // depending on if the current object
  8.    // is equal, greater or lesser than the other object
  9.   // Any property can be used to make
  10.   // that comparison. Let us assume that this implementation
  11.   //  uses the accountNumber property. Then the sort
  12.   // would happen on the basis of the account numbers
  13.  
  14.   }

The limitation of the above usage is that only one kind of sort (on the basis of accountNumber) is possible.

To address the need for sorting by other or multiple sort criteria, the API adds another static method to the Collections class.
The second variant is

Collections.sort(List list,Comparator comparator);

This variant utilizes the comparator to determine the ordering of the items participating in the sort. Hence the ordering of the elements in this approach need not be the “natural” sorting order. Hence a list of Account objects can now be sorted by the account number or balance or any other property that is available in the Account class.

These two variants while being powerful are not sufficient to cater to sorting requirements in real applications. Hence the need arises to build on the basic blocks provided by the Collections.sort() method and accomplish complex sorts.

This article would discuss these strategies.

Some typical requirements for sorting are enumerated below:

  • Applications (whether they are web based or otherwise) need the ability to sort by multiple criteria. These criteria would have to be passed during run time.
  • Part of a clean sorting design should also involve the design of domain objects (or DTOs) that would specify these criteria.
  • The sorting algorithm should be extended to cater to sorting by multiple criteria. Ideally, it should be able to work on any domain object without the object implementing particular interfaces such as Comparable.
  • Sorting design should also be well integrated with “pagination” design as these two concerns go hand in hand.

Here is a simple class that would specify the SortCriterion.It defines if it is an ascending or descending sort and the criterion that should be used to do the sorting. The criterion can be a column name or a column index.

  1.   /**
  2.      * Name of the criterion. Typically the column name to sort by.
  3.      */
  4.     private String name;
  5.     // index of the criterion. The order of the thing.
  6.     private int index;
  7.  
  8.     /**
  9.      * Is this an ascending sort ??
  10.      */
  11.     private boolean ascendingOrder = true;

Since we do want the ability to sort by multiple sort criteria there should be another class that contains the different sort criteria. Here is a SortCriteria class. It contains a list of SortCriterion objects.
We don’t want to write a sorting algorithm (Collections.sort() performs well enough). But we do want to incorporate our SortCriteria class and accomplish the sorting.
We don’t want to modify the model object that is stored in the list. We cannot create a new compareTo() implementation for it based on the passed sort criteria(hey this is not ruby where we can have method over-rides at the instance level) Hence we cannot use the Collections.sort(list) signature but would have to use the second form of the sort method namely Collections.sort(List,Comparator).
We will have to write a Comparator that is able to handle the sortCriteria passed to determine the order of the sort itself. Further we also would like the model object to have a say (if it desires) on the sorting. To accomplish these apparently conflicting objectives we write first an interface Sortable and a GenericComparator.
The Sortable interface just enhances the compareTo() method to accept a sort criterion which is just a string that can be used to determine the order of sorting. Here it is

  1.  public interface Sortable {
  2.     /**
  3.      * @param sortCriterion –
  4.      *            a field name to sort by
  5.      * @param other –
  6.      *            The other object to compare against.
  7.      * @return -1 , 0 or +1 (same as java.util.Comparable)
  8.      */
  9.     int compareTo(String sortCriterion, Object other);
  10. }

This does not have to handle ascending and descending sorts or a list of sort criteria. The onus is on the GenericComparator class. Please look at it here.
This class looks at each SortCriterion passed and tries to compare the passed argument with the current one. It uses the column name that was passed as a field within the domain object to do the compareTo(). If the object implements Sortable then the method is invoked. Lower levels of sorts would only be needed if two objects are equal for a higher level sort. (ex:if the sort has to be by account number and balance then the balance compare is only required if the account numbers are the same)
Finally, we are ready to write our SortCommand. Here is a snippet of code.

  1. public void execute(List list, SortCriteria sortCriteria){
  2.  
  3.    GenericComparator gc = new GenericComparator(sortCriteria);
  4.    Collections.sort(list,gc);
  5.  
  6. }

As simple as that! Now we can sort any kind of list based on complex sort criteria.

Link to code.
Be Sociable, Share!

 Raja has been blogging in this forum since 2006. He loves a technical discussion any day. He finds life incomplete without a handy whiteboard and a marker.


Tags: , ,

2 comments
Leave a comment »

  1. Multi-Column Sorting in Java
    I read your column it kinda made sense. I really need to see the entire source to understand. Is it possible to email me the source. I would appreciate it.

    Thanx…

  2. Randy,

    The source for generic comparator can be found at http://www.thekollurus.com/code/sorting/GenericComparator.java. The other stuff such as SortCriterion and SortCriteria are simple data containers which can be found inline in the post.

    Please let me know if you need anything else.
    raja

Leave Comment