# Java Notes

# 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
    // File: arrays/filelist/Filelistsort.java
    // Purpose: List contents of user home directory.
    //          Demonstrates use of Comparators to sort the
    //          same array by two different criteria.
    // Author: Fred Swartz 2006-Aug-23  Public domain.

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

    public class Filelistsort {

        //======================================================= main
        public static void main(String[] args) {
            //... Create comparators for sorting.
            Comparator<File> byDirThenAlpha = new DirAlphaComparator();
            Comparator<File> byNameLength   = new NameLengthComparator();

            //... Create a File object for user directory.
            File dir = new File(System.getProperty("user.home"));
            File[] children = dir.listFiles();

            System.out.println("Files by directory, then alphabetical");
            Arrays.sort(children, byDirThenAlpha);
            printFileNames(children);

            System.out.println("Files by length of name (long first)");
            Arrays.sort(children, byNameLength);
            printFileNames(children);
        }

        //============================================= printFileNames
        private static void printFileNames(File[] fa){
            for (File oneEntry : fa) {
                System.out.println("   " + oneEntry.getName());
            }
        }
    }

    ////////////////////////////////////////////////// DirAlphaComparator
    // To sort directories before files, then alphabetically.
    class DirAlphaComparator 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());
            }
        }
    }

    ////////////////////////////////////////////////// NameLengthComparator
    // To sort by length of file/directory name (longest first).
    class NameLengthComparator 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.