Sunday, December 4, 2011

Specifying how to sort data in Java: Comparators

Specifying how to sort data in Java: Comparators

If you've seen the previous posts you'll know that -

So far, we've seen how to sort data and that Java is "naturally" sortable, i.e. implements the Comparable interface, or else make our own data implement Comparable so that it can be sorted. But of course this model has limitations:

if the class in question doesn't already implement Comparable– or doesn't implement it in the way you want– and you can't subclass it, then implementing Comparable isn't an option;
a single Comparable implementation is awkward if you want different sorting modes for the same class.
Java gets round these limitations with another interface, Comparator. A Comparator implementation provides a method specifying how any two objects of a given class are to be ordered. To specify how a collection of objects is to be sorted, Java then provides various places where we can "plug in" a Comparator of our choosing.

Below, we dive in and look at an example Comparator for sorting Strings by length.

Comparator example: sorting Strings by length

We introduced the notion of a Comparator in Java, which is used to specify the sort order of a particular class. Let's start with an example to sort Strings by their length. We thus want to write a Comparator that compares Strings. So the general format of our Comparator will be as follows:


public class StringLengthComparator implements Comparator {
  public int compare(String o1, String o2) {
    return ...
  }
}


Now, we just need to make the compare() return method return an appropriate value to indicate the ordering. Effectively, the logic of this method should be o1.compareTo(o2). That is– as discussed when we reviewed sorting_comparable_compareto(in previous post) the compareTo() method– it should return:

a negative number if (and only if) o1 comes before o2;
a positive number if (and only if) o1 comes after o2;
else 0.
So a simple implementation would be1:


public class StringLengthComparator implements Comparator {
  public int compare(String o1, String o2) {
    if (o1.length() < o2.length()) {
      return -1;
    } else if (o1.length() > o2.length()) {
      return 1;
    } else {
      return 0;
    }
  }
}


Now, armed with our Comparator and some vital string data that we need ordering by length:


String[] strs = {"boxer shorts", "grundies", "boxers",
  "elasticated Y-fronts", "underpants", "briefs"};


we can sort our string data by length with a simple call to Arrays.sort(), this time passing in an instance of our parameter:


// Sort
Arrays.sort(strs, new StringLengthComparator());
// Print the results
for (String s : strs)
  System.out.println(s);


And lo and behold, our garments are sorted in correct lengthwise order:


boxers
briefs
grundies
underpants
boxer shorts
elasticated Y-fronts


Note that, as discussed on the Java sort algorithm, the sort is stable. That is, strings with the same length are guaranteed not to be reversed, and so our boxers correctly precede our briefs.

Note 1: 1. Some programmers prefer the more succinct version return o1.length() < o2.length() ? -1 : (o1.length() > o2.length() ? 1 : 0);. It is also presumably safe to use a subtraction– on 32-bit architecture at least, it's impossible to have Java Strings long enough to overflow when doing the subtraction! (from: Javamex.com)

No comments:

Post a Comment