Java: Comparators

Defining your own sort order

The primary use of comparators is to pass them to something that does sorting, either one of the explicit sort methods, or to a data structure than implicitly sorts (eg, TreeSet or TreeMap).

java.util.Comparator interface

The java.util.Comparator interface can be used to create objects to pass to sort methods or sorting data structures. A Comparator must define a compare function which takes two Objects and returns a -1, 0, or 1

Comparators not needed if there's a natural sorting order

Comparators are not needed for arrays of primitive values, or arrays of collections of objects that have a natural ordering, eg, String, BigInteger, etc.

String also has a predefined comparator for case insensitive sorting,
String.CASE_INSENSITIVE_ORDER .

Example

The example below gets the subfiles (children) of a directory, and sorts them two different ways.

  1 
  2 
  3 
  4 
  5 
  6 
  7 
  8 
  9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
 36 
 37 
 38 
 39 
 40 
 41 
 42 
 43 
 44 
 45 
 46 
 47 
 48 
 49 
 50 
 51 
 52 
 53 
 54 
 55 
 56 
 57 
 58 
 59 
 60 
 61 
 62 
 63 
 64 
 65 
 66 
 67 
 68 
 69 
 70 
 71 
 72 
 73 
 74 
 75 
 76 
 77 
 78 
 79 
// File: arrays/filelist/Filelistsort.java
// Purpose: List contents of currrent diectory (.)
//          Demonstrates use of Comparators.
//          Java 5: Generics and for each loop.
// Author: Fred Swartz
// Date  : 2005-Feb-22

import java.util.Arrays;
import java.util.Comparator;
import java.io.*;

public class Filelistsort {

    //======================================================= main
    public static void main(String[] args) {
        //... Create some comparators that we'll use for sort.
        Comparator<File> fileComp = new FileComparator();
        Comparator<File> longComp = new LongNamesFirstComparator();

        //... Create a File object for the current directory.
        File dir = new File(".");
        File[] children = dir.listFiles();

        //.. Print out the names in one order.
        System.out.println("Files by directory, then alphabetical");
        Arrays.sort(children, fileComp); // Sort using a comparator.
        for (File oneEntry : children) {
            System.out.println("   " + oneEntry.getName());
        }

        //.. Print out the names in another order.
        System.out.println("Files by length of name (long first)");
        Arrays.sort(children, longComp); // Sort using a comparator.
        for (File oneEntry : children) {
            System.out.println("   " + oneEntry.getName());
        }
    }
}


//////////////////////////////////////////////////// FileComparator
// This comparator will compare two File objects and
// return -1, 0, or +1 depending on their relative order.
class FileComparator implements Comparator<File> {

    // Comparator interface requires defining compare method.
    public int compare(File filea, File fileb) {
        //... Sort directories before files,
        //    otherwise alphabetical ignoring case.
        if (filea.isDirectory() && !fileb.isDirectory()) {
            return -1;

        } else if (!filea.isDirectory() && fileb.isDirectory()) {
            return 1;

        } else {
            return filea.getName().compareToIgnoreCase(fileb.getName());
        }
    }
}


/////////////////////////////////////////// LongNamesFirstComparator
// This comparator will compare two File objects and
// return -1, 0, or +1 depending on their name sizes
class LongNamesFirstComparator implements Comparator<File> {

    // Comparator interface requires defining compare method.
    public int compare(File filea, File fileb) {
        int comp = fileb.getName().length() - filea.getName().length();
        if (comp != 0) {
            //... If different lengths, we're done.
            return comp;
        } else {
            //... If equal lengths, sort alphabetically.
            return filea.getName().compareToIgnoreCase(fileb.getName());
        }
    }
}

Exercise - Sort CSV files

Data can be exported from a spreadsheet program where each row is represented as a line of text with values separated by commas (CSV = Comma Separated Values).

A common problem is to sort these files based on one column. One approach would be to read in each line, split it based on commas into an array of strings. Successively add these strings to an ArrayList and sort the ArrayList by defining a Comparator that sorts on a speficific column.