Saturday, May 10, 2014

Using Comparator to change sort technique in Java

Java provides ability to sort an array (or collection ), if the contained type properly implements java.lang.Comparable<T> interface. If type is comparable; sort method from Arrays class can be used for sorting the container (array or collection). This same utility is used by Collections API as well. You can design a type keeping in mind a natural sorting techniques, but there could still be a possibility to sort it differently. In such scenario, it doesn't make sense to go back to the class and modify the definition of the method. Some time, it might not be even feasible (to modify the class)!

In this post, I will be mentioning how can we provide a different ordering technique (other than one provided by class). The approach discussed in the post is applicable for any type (inbuilt or custom); but to make it simpler, I have considered Java's inbuilt type, String. Let's start with an example :

 String[] country = { "India", "US", "France" };  
 Arrays.sort(country);  
 System.out.println(Arrays.toString(country));  
 // Output : [France, India, US]  

Above snippet is able to sort array of strings because String class implements Comparable interface (i.e. provides implementation of compareTo(..) method)
To sort collections; Collections.sort(..) can be used.

Providing Custom Comparison 


So default comparison provided by String class, sorts the array in ascending order. What if you have to sort the above array in descending order?
Now modifying the compareTo(..) method of the String class is out of question (ditto the case, if you using a type from a jar). 

This is where the need for alternative comparison or ordering technique arises. Java provides another interface java.util.Comparator<T> to impose ordering on some collection of objects. This interface has compare(..) method to compare two objects of same type. So, we can create a Comparator<String> instance and pass it to the sort method. 

 import java.util.Comparator;  
 public class MyComparator implements Comparator<String> {  
      @Override  
      public int compare(String o1, String o2) {  
           return o2.compareTo(o1);  
      }  
 }  
 MyComparator my = new MyComparator();  
 Arrays.sort(country, my);  
 System.out.println(Arrays.toString(country));  
 //Output : [US, India, France]  

Note that the compare method in MyComparator class is basically calling compareTo method provided by String class. It has just reversed the order to reverse sort the array.

Java provides an inbuilt method to sort a collection in reverse order. So we don't need to re-invent the wheel but we should be aware of the logic.
Arrays.sort(country, Collections.reverseOrder());

Above approach is bit verbose; we can use anonymous class to make it more compact.
 import java.util.Arrays;  
 import java.util.Comparator;  
 public class OverrideDefaultSort {  
      public static String[] reverseSort(String[] country) {  
           Comparator<String> c = new Comparator<String>() {  
                @Override  
                public int compare(String o1, String o2) {  
                     return o2.compareTo(o1);  
                }  
           };  
           Arrays.sort(country, c);  
           return country;  
      }  
      public static void main(String[] args) {  
           String[] country = { "India", "US", "France" };  
           String[] c = OverrideDefaultSort.reverseSort(country);  
           System.out.println("Reverse Ordering:" + Arrays.toString(c));  
      }  
 }  
Output:
Natural Orering:[France, India, US]
Reverse Ordering:[US, India, France]

So second argument of sort method can take any comparator. Also above code can be even compacted further and Comparator can be provided inline inside the sort method. Below snippet sorts the array by size (or length) of the String.

 Arrays.sort(country, new Comparator<String>(){  
   @Override  
   public int compare(String o1, String o2) {  
       return Integer.compare(o1.length(), o2.length());  
   }  
 });  
Output:
Sort by length:[US, India, France]

So, sort in as many ways as you may wish !!!



No comments:

Post a Comment