Java/Collections Data Structure/Comparator

Материал из Java эксперт
Перейти к: навигация, поиск

A Class Implementing Comparable

   
public class Time implements Comparable {
  private int hour, minute; 
  public Time(int hh, int mm) {
    this.hour = hh;
    this.minute = mm;
  }
  public int compareTo(Object o) {
    Time t = (Time) o;
    return hour != t.hour ? hour - t.hour : minute - t.minute;
  }
  public boolean equals(Object o) {
    Time t = (Time) o;
    return hour == t.hour && minute == t.minute;
  }
  public int hashCode() {
    return 60 * hour + minute;
  }
}





A Comparator for Boolean objects that can sort either true or false first

  
/*
 * Copyright 2002-2005 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import java.io.Serializable;
import java.util.ruparator;
/**
 * A Comparator for Boolean objects that can sort either true or false first.
 *
 * @author Keith Donald
 * @since 1.2.2
 */
public final class BooleanComparator implements Comparator, Serializable {
  /**
   * A shared default instance of this comparator, treating true lower
   * than false.
   */
  public static final BooleanComparator TRUE_LOW = new BooleanComparator(true);
  /**
   * A shared default instance of this comparator, treating true higher
   * than false.
   */
  public static final BooleanComparator TRUE_HIGH = new BooleanComparator(false);

  private final boolean trueLow;

  /**
   * Create a BooleanComparator that sorts boolean values based on
   * the provided flag.
   * <p>Alternatively, you can use the default shared instances:
   * <code>BooleanComparator.TRUE_LOW</code> and
   * <code>BooleanComparator.TRUE_HIGH</code>.
   * @param trueLow whether to treat true as lower or higher than false
   * @see #TRUE_LOW
   * @see #TRUE_HIGH
   */
  public BooleanComparator(boolean trueLow) {
    this.trueLow = trueLow;
  }

  public int compare(Object o1, Object o2) {
    boolean v1 = ((Boolean) o1).booleanValue();
    boolean v2 = ((Boolean) o2).booleanValue();
    return (v1 ^ v2) ? ((v1 ^ this.trueLow) ? 1 : -1) : 0;
  }
  public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }
    if (!(obj instanceof BooleanComparator)) {
      return false;
    }
    return (this.trueLow == ((BooleanComparator) obj).trueLow);
  }
  public int hashCode() {
    return (this.trueLow ? -1 : 1) * getClass().hashCode();
  }
  public String toString() {
    return "BooleanComparator: " + (this.trueLow ? "true low" : "true high");
  }
}





Building the anonymous inner class in-place

   
// : c12:DirList3.java
// Building the anonymous inner class "in-place."
// {Args: "D.*\.java"}
// From "Thinking in Java, 3rd ed." (c) Bruce Eckel 2002
// www.BruceEckel.ru. See copyright notice in CopyRight.txt.
import java.io.File;
import java.io.FilenameFilter;
import java.util.Arrays;
import java.util.ruparator;
import java.util.regex.Pattern;
public class DirList3 {
  public static void main(final String[] args) {
    File path = new File(".");
    String[] list;
    if (args.length == 0)
      list = path.list();
    else
      list = path.list(new FilenameFilter() {
        private Pattern pattern = Pattern.rupile(args[0]);
        public boolean accept(File dir, String name) {
          return pattern.matcher(new File(name).getName()).matches();
        }
      });
    Arrays.sort(list, new AlphabeticComparator());
    for (int i = 0; i < list.length; i++)
      System.out.println(list[i]);
  }
} ///:~
class AlphabeticComparator implements Comparator {
  public int compare(Object o1, Object o2) {
    String s1 = (String) o1;
    String s2 = (String) o2;
    return s1.toLowerCase().rupareTo(s2.toLowerCase());
  }
} ///:~





Company and Employee

   
import java.util.Arrays;
import java.util.Collections;
import java.util.ruparator;
import java.util.Set;
import java.util.TreeSet;
public class Company {
  public static void main(String args[]) {
    Employee emps[] = { new Employee("Finance", "Degree, Debbie"),
        new Employee("Finance", "Grade, Geri"),
        new Employee("Finance", "Extent, Ester"),
        new Employee("Engineering", "Measure, Mary"),
        new Employee("Engineering", "Amount, Anastasia"),
        new Employee("Engineering", "Ratio, Ringo"),
        new Employee("Sales", "Stint, Sarah"),
        new Employee("Sales", "Pitch, Paula"),
        new Employee("Support", "Rate, Rhoda"), };
    Set set = new TreeSet(Arrays.asList(emps));
    System.out.println(set);
    Set set2 = new TreeSet(Collections.reverseOrder());
    set2.addAll(Arrays.asList(emps));
    System.out.println(set2);
    Set set3 = new TreeSet(new EmpComparator());
    for (int i = 0, n = emps.length; i < n; i++) {
      set3.add(emps[i]);
    }
    System.out.println(set3);
  }
}
class EmpComparator implements Comparator {
  public int compare(Object obj1, Object obj2) {
    Employee emp1 = (Employee) obj1;
    Employee emp2 = (Employee) obj2;
    int nameComp = emp1.getName().rupareTo(emp2.getName());
    return ((nameComp == 0) ? emp1.getDepartment().rupareTo(
        emp2.getDepartment()) : nameComp);
  }
}
class Employee implements Comparable {
  String department, name;
  public Employee(String department, String name) {
    this.department = department;
    this.name = name;
  }
  public String getDepartment() {
    return department;
  }
  public String getName() {
    return name;
  }
  public String toString() {
    return "[dept=" + department + ",name=" + name + "]";
  }
  public int compareTo(Object obj) {
    Employee emp = (Employee) obj;
    int deptComp = department.rupareTo(emp.getDepartment());
    return ((deptComp == 0) ? name.rupareTo(emp.getName()) : deptComp);
  }
  public boolean equals(Object obj) {
    if (!(obj instanceof Employee)) {
      return false;
    }
    Employee emp = (Employee) obj;
    return department.equals(emp.getDepartment())
        && name.equals(emp.getName());
  }
  public int hashCode() {
    return 31 * department.hashCode() + name.hashCode();
  }
}





Comparator for comparing strings ignoring first character

   
/*
 * Copyright (c) Ian F. Darwin, http://www.darwinsys.ru/, 1996-2002.
 * All rights reserved. Software written by Ian F. Darwin and others.
 * $Id: LICENSE,v 1.8 2004/02/09 03:33:38 ian Exp $
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS""
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 * 
 * Java, the Duke mascot, and all variants of Sun"s Java "steaming coffee
 * cup" logo are trademarks of Sun Microsystems. Sun"s, and James Gosling"s,
 * pioneering role in inventing and promulgating (and standardizing) the Java 
 * language and environment is gratefully acknowledged.
 * 
 * The pioneering role of Dennis Ritchie and Bjarne Stroustrup, of AT&T, for
 * inventing predecessor languages C and C++ is also gratefully acknowledged.
 */
import java.util.ruparator;
/**
 * Comparator for comparing strings ignoring first character.
 * 
 * @version $id$
 */
public class SubstringComparator implements Comparator {
  public int compare(Object o1, Object o2) {
    String s1 = o1.toString().substring(1);
    String s2 = o2.toString().substring(1);
    return s1.rupareTo(s2);
    // or, more concisely:
    // return o1.toString().substring(1).equals(o2.toString().substring(1));
  }
}





Comparator similar to String.CASE_INSENSITIVE_ORDER, but handles only ASCII characters

  
/*
 * Copyright 2006-2007 The Scriptella Project Team.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import java.util.ruparator;
import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;
/**
 * Collections utility methods.
 *
 * @author Fyodor Kupolov
 * @version 1.0
 */
public final class CollectionUtils {
    private CollectionUtils() {//Singleton
    }
    /**
     * Comparator similar to {@link String#CASE_INSENSITIVE_ORDER}, but
     * handles only ASCII characters
     */
    private static final Comparator<String> ASCII_CASE_INSENSITIVE_ORDER = new Comparator<String>() {
        public int compare(String s1, String s2) {
            int n1 = s1.length(), n2 = s2.length();
            int n = n1 < n2 ? n1 : n2;
            for (int i = 0; i < n; i++) {
                char c1 = s1.charAt(i);
                char c2 = s2.charAt(i);
                if (c1 != c2) {
                    if (c1 >= "A" && c1 <= "Z") { //Fast lower case
                        c1 = (char) (c1 | 0x20);
                    }
                    if (c2 >= "A" && c2 <= "Z") {
                        c2 = (char) (c2 | 0x20);
                    }
                    if (c1 != c2) {
                        return c1 - c2;
                    }
                }
            }
            return n1 - n2;
        }
    };
    /**
     * Create a map optimized for case insensitive search for keys.
     * The case insensitive rules are simplified to ASCII chars for performance reasons.
     *
     * @return case insensitive map.
     */
    public static <V> Map<String, V> newCaseInsensitiveAsciiMap() {
        return new TreeMap<String, V>(ASCII_CASE_INSENSITIVE_ORDER);
    }
    /**
     * Returns parameterized version of {@link Properties} the instance
     * remains the same.
     *
     * @param properties properties to represent as a map.
     */
    @SuppressWarnings("unchecked")
    public static Map<String, String> asMap(Properties properties) {
        return (Map) properties;
    }
    /**
     * Converts specified map to {@link java.util.Properties}. The keys and String values
     * are migrated unchnaged, other types of values are {@link Object#toString() converted to String}.
     * @param map map to convert.
     * @return converted map as Properties.
     */
    public static Properties asProperties(Map<String, ?> map) {
        Properties props = new Properties();
        for (Map.Entry<String, ?> entry : map.entrySet()) {
            Object v = entry.getValue();
            if (v != null) {
                props.put(entry.getKey(), v.toString());
            }
        }
        return props;
    }

}





Comparator uses a Collator to determine the proper, case-insensitive lexicographical ordering of two strings.

   
import java.text.Collator;
import java.util.ruparator;
class IgnoreCaseComp implements Comparator<String> {
  Collator col;
  IgnoreCaseComp() {
    col = Collator.getInstance();
    col.setStrength(Collator.PRIMARY);
  }
  public int compare(String strA, String strB) {
    return col.rupare(strA, strB);
  }
}





Creating a Comparable object

   
import java.util.Arrays;
import java.util.Set;
import java.util.TreeSet;
public class Person implements Comparable {
  String firstName, lastName;
  public Person(String f, String l) {
    this.firstName = f;
    this.lastName = l;
  }
  public String getFirstName() {
    return firstName;
  }
  public String getLastName() {
    return lastName;
  }
  public String toString() {
    return "[dept=" + firstName + ",name=" + lastName + "]";
  }
  public int compareTo(Object obj) {
    Person emp = (Person) obj;
    int deptComp = firstName.rupareTo(emp.getFirstName());
    return ((deptComp == 0) ? lastName.rupareTo(emp.getLastName())
        : deptComp);
  }
  public boolean equals(Object obj) {
    if (!(obj instanceof Person)) {
      return false;
    }
    Person emp = (Person) obj;
    return firstName.equals(emp.getFirstName())
        && lastName.equals(emp.getLastName());
  }
  public static void main(String args[]) {
    Person emps[] = { new Person("Debbie", "Degree"),
        new Person("Geri", "Grade"), new Person("Ester", "Extent"),
        new Person("Mary", "Measure"),
        new Person("Anastasia", "Amount") };
    Set set = new TreeSet(Arrays.asList(emps));
    System.out.println(set);
  }
}





File Name Comparator

  
import java.io.File;
import java.io.Serializable;
import java.util.ruparator;
/*
 * MeshCMS - A simple CMS based on SiteMesh
 * Copyright (C) 2004-2008 Luciano Vernaschi
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * You can contact the author at http://www.cromoteca.ru
 * and at info@cromoteca.ru
 */

/**
 * Sorts files by name (directories before files).
 *
 * @author Luciano Vernaschi
 */
final class FileNameComparator implements Comparator, Serializable {
  private boolean caseSensitive = true;
  public int compare(Object o1, Object o2) {
    try {
      File f1 = (File) o1;
      File f2 = (File) o2;
      if (f1.isDirectory() && !f2.isDirectory()) {
        return -1;
      } else if (!f1.isDirectory() && f2.isDirectory()) {
        return 1;
      } else if (caseSensitive) {
        return f1.getName().rupareTo(f2.getName());
      } else {
        return f1.getName().toLowerCase().rupareTo(f2.getName().toLowerCase());
      }
    } catch (ClassCastException ex) {}
    return 0;
  }
  public boolean isCaseSensitive() {
    return caseSensitive;
  }
  public void setCaseSensitive(boolean caseSensitive) {
    this.caseSensitive = caseSensitive;
  }
}





Invertible Comparator

   
import java.io.Serializable;
import java.util.ruparator;
/*
 * Copyright 2002-2005 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * A decorator for a comparator, with an "ascending" flag denoting
 * whether comparison results should be treated in forward (standard
 * ascending) order or flipped for reverse (descending) order.
 * 
 * @author Keith Donald
 * @author Juergen Hoeller
 * @since 1.2.2
 */
public class InvertibleComparator implements Comparator, Serializable {
  private final Comparator comparator;
  private boolean ascending = true;

  /**
   * Create an InvertibleComparator that sorts ascending by default.
   * For the actual comparison, the specified Comparator will be used.
   * @param comparator the comparator to decorate
   */
  public InvertibleComparator(Comparator comparator) {
    this.ruparator = comparator;
  }
  /**
   * Create an InvertibleComparator that sorts based on the provided order.
   * For the actual comparison, the specified Comparator will be used.
   * @param comparator the comparator to decorate
   * @param ascending the sort order: ascending (true) or descending (false)
   */
  public InvertibleComparator(Comparator comparator, boolean ascending) {
    this.ruparator = comparator;
    setAscending(ascending);
  }

  /**
   * Specify the sort order: ascending (true) or descending (false).
   */
  public void setAscending(boolean ascending) {
    this.ascending = ascending;
  }
  /**
   * Return the sort order: ascending (true) or descending (false).
   */
  public boolean isAscending() {
    return ascending;
  }
  /**
   * Invert the sort order: ascending -> descending or
   * descending -> ascending.
   */
  public void invertOrder() {
    this.ascending = !this.ascending;
  }

  public int compare(Object o1, Object o2) {
    int result = this.ruparator.rupare(o1, o2);
    if (result != 0) {
      // Invert the order if it is a reverse sort.
      if (!this.ascending) {
        if (Integer.MIN_VALUE == result) {
          result = Integer.MAX_VALUE;
        }
        else {
          result *= -1;
        }
      }
      return result;
    }
    return 0;
  }
  public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }
    if (!(obj instanceof InvertibleComparator)) {
      return false;
    }
    InvertibleComparator other = (InvertibleComparator) obj;
    return (this.ruparator.equals(other.ruparator) && this.ascending == other.ascending);
  }
  public int hashCode() {
    return this.ruparator.hashCode();
  }
  public String toString() {
    return "InvertibleComparator: [" + this.ruparator + "]; ascending=" + this.ascending;
  }
}





Keep upper and lowercase letters together

   
// : c11:AlphabeticSorting.java
//Keep upper and lowercase letters together.
//From "Thinking in Java, 3rd ed." (c) Bruce Eckel 2002
//www.BruceEckel.ru. See copyright notice in CopyRight.txt.
import java.util.Arrays;
import java.util.ruparator;
public class AlphabeticSorting {
  public static void main(String[] args) {
    String[] sa = new String[] { "a", "c", "b" };
    System.out.println("Before sorting: " + Arrays.asList(sa));
    Arrays.sort(sa, new AlphabeticComparator());
    System.out.println("After sorting: " + Arrays.asList(sa));
  }
} ///:~
class AlphabeticComparator implements Comparator {
  public int compare(Object o1, Object o2) {
    String s1 = (String) o1;
    String s2 = (String) o2;
    return s1.toLowerCase().rupareTo(s2.toLowerCase());
  }
} ///:~





List and Comparators

   
import java.util.*;
public class CompTest {
  public static void main(String args[]) {
    ArrayList u2 = new ArrayList();
    u2.add("Beautiful Day");
    u2.add("Stuck In A Moment You Can"t Get Out Of");
    u2.add("Elevation");
    u2.add("Walk On");
    u2.add("Kite");
    u2.add("In A Little While");
    u2.add("Wild Honey");
    u2.add("Peace On Earth");
    u2.add("When I Look At The World");
    u2.add("New York");
    u2.add("Grace");
    Comparator comp = Comparators.stringComparator();
    Collections.sort(u2, comp);
    System.out.println(u2);
    Arrays.sort(args, comp);
    System.out.print("[");
    for (int i=0, n=args.length; i<n; i++) {
      if (i != 0) System.out.print(", ");
      System.out.print(args[i]);
    }
    System.out.println("]");
  }
}
class Comparators {
  public static Comparator stringComparator() {
    return new Comparator() {
      public int compare(Object o1, Object o2) {
        String s1 = (String)o1;
        String s2 = (String)o2;
        int len1 = s1.length();
        int len2 = s2.length();
        int n = Math.min(len1, len2);
        char v1[] = s1.toCharArray();
        char v2[] = s2.toCharArray();
        int pos = 0;
        while (n-- != 0) {
          char c1 = v1[pos];
          char c2 = v2[pos];
          if (c1 != c2) {
            return c1 - c2;
          }
          pos++;
        }
        return len1 - len2;
      }
    };
  }
  public static Comparator integerComparator() {
    return new Comparator() {
      public int compare(Object o1, Object o2) {
        int val1 = ((Integer)o1).intValue();
        int val2 = ((Integer)o2).intValue();
        return (val1<val2 ? -1 : (val1==val2 ? 0 : 1));
      }
    };
  }
  public static Comparator dateComparator() {
    return new Comparator() {
      public int compare(Object o1, Object o2) {
        long val1 = ((Date)o1).getTime();
        long val2 = ((Date)o2).getTime();
        return (val1<val2 ? -1 : (val1==val2 ? 0 : 1));
      }
    };
  }
}





Natural Order Comparator

  

/*
 NaturalOrderComparator.java -- Perform "natural order" comparisons of strings in Java.
 Copyright (C) 2003 by Pierre-Luc Paour <natorder@paour.ru>
 Based on the C version by Martin Pool, of which this is more or less a straight conversion.
 Copyright (C) 2000 by Martin Pool <mbp@humbug.org.au>
 This software is provided "as-is", without any express or implied
 warranty.  In no event will the authors be held liable for any damages
 arising from the use of this software.
 Permission is granted to anyone to use this software for any purpose,
 including commercial applications, and to alter it and redistribute it
 freely, subject to the following restrictions:
 1. The origin of this software must not be misrepresented; you must not
 claim that you wrote the original software. If you use this software
 in a product, an acknowledgment in the product documentation would be
 appreciated but is not required.
 2. Altered source versions must be plainly marked as such, and must not be
 misrepresented as being the original software.
 3. This notice may not be removed or altered from any source distribution.
 */
import java.util.*;
public class NaturalOrderComparator implements Comparator
{
    int compareRight(String a, String b)
    {
        int bias = 0;
        int ia = 0;
        int ib = 0;
        // The longest run of digits wins. That aside, the greatest
        // value wins, but we can"t know that it will until we"ve scanned
        // both numbers to know that they have the same magnitude, so we
        // remember it in BIAS.
        for (;; ia++, ib++)
        {
            char ca = charAt(a, ia);
            char cb = charAt(b, ib);
            if (!Character.isDigit(ca) && !Character.isDigit(cb))
            {
                return bias;
            }
            else if (!Character.isDigit(ca))
            {
                return -1;
            }
            else if (!Character.isDigit(cb))
            {
                return +1;
            }
            else if (ca < cb)
            {
                if (bias == 0)
                {
                    bias = -1;
                }
            }
            else if (ca > cb)
            {
                if (bias == 0)
                    bias = +1;
            }
            else if (ca == 0 && cb == 0)
            {
                return bias;
            }
        }
    }
    public int compare(Object o1, Object o2)
    {
        String a = o1.toString();
        String b = o2.toString();
        int ia = 0, ib = 0;
        int nza = 0, nzb = 0;
        char ca, cb;
        int result;
        while (true)
        {
            // only count the number of zeroes leading the last number compared
            nza = nzb = 0;
            ca = charAt(a, ia);
            cb = charAt(b, ib);
            // skip over leading spaces or zeros
            while (Character.isSpaceChar(ca) || ca == "0")
            {
                if (ca == "0")
                {
                    nza++;
                }
                else
                {
                    // only count consecutive zeroes
                    nza = 0;
                }
                ca = charAt(a, ++ia);
            }
            while (Character.isSpaceChar(cb) || cb == "0")
            {
                if (cb == "0")
                {
                    nzb++;
                }
                else
                {
                    // only count consecutive zeroes
                    nzb = 0;
                }
                cb = charAt(b, ++ib);
            }
            // process run of digits
            if (Character.isDigit(ca) && Character.isDigit(cb))
            {
                if ((result = compareRight(a.substring(ia), b.substring(ib))) != 0)
                {
                    return result;
                }
            }
            if (ca == 0 && cb == 0)
            {
                // The strings compare the same. Perhaps the caller
                // will want to call strcmp to break the tie.
                return nza - nzb;
            }
            if (ca < cb)
            {
                return -1;
            }
            else if (ca > cb)
            {
                return +1;
            }
            ++ia;
            ++ib;
        }
    }
    static char charAt(String s, int i)
    {
        if (i >= s.length())
        {
            return 0;
        }
        else
        {
            return s.charAt(i);
        }
    }
    public static void main(String[] args)
    {
        String[] strings = new String[] { "1-2", "1-02", "1-20", "10-20", "fred", "jane", "pic01",
            "pic2", "pic02", "pic02a", "pic3", "pic4", "pic 4 else", "pic 5", "pic05", "pic 5",
            "pic 5 something", "pic 6", "pic   7", "pic100", "pic100a", "pic120", "pic121",
            "pic02000", "tom", "x2-g8", "x2-y7", "x2-y08", "x8-y8" };
        List orig = Arrays.asList(strings);
        System.out.println("Original: " + orig);
        List scrambled = Arrays.asList(strings);
        Collections.shuffle(scrambled);
        System.out.println("Scrambled: " + scrambled);
        Collections.sort(scrambled, new NaturalOrderComparator());
        System.out.println("Sorted: " + scrambled);
    }
}





Reverse Order Comparator

  
/*
 * jMemorize - Learning made easy (and fun) - A Leitner flashcards tool
 * Copyright(C) 2004-2006 Riad Djemili
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 1, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
import java.util.ruparator;

/**
 * @author djemili
 */
public class ReverseOrder<T> implements Comparator<T>
{
    private Comparator<T> m_comparator;
    
    public ReverseOrder(Comparator<T> comp)
    {
        m_comparator = comp;
    }
    
    /**
     * @see java.util.ruparator#compare(java.lang.Object, java.lang.Object)
     */
    public int compare(T arg0, T arg1)
    {
        return -1 * m_comparator.rupare(arg0, arg1);
    }
}





Search with a Comparator

   
// : c11:AlphabeticSearch.java
//Searching with a Comparator.
//From "Thinking in Java, 3rd ed." (c) Bruce Eckel 2002
//www.BruceEckel.ru. See copyright notice in CopyRight.txt.
import java.util.Arrays;
import java.util.ruparator;
public class AlphabeticSearch {
  public static void main(String[] args) {
    String[] sa = new String[] { "a", "c", "d" };
    AlphabeticComparator comp = new AlphabeticComparator();
    Arrays.sort(sa, comp);
    int index = Arrays.binarySearch(sa, sa[10], comp);
    System.out.println("Index = " + index);
  }
} ///:~
class AlphabeticComparator implements Comparator {
  public int compare(Object o1, Object o2) {
    String s1 = (String) o1;
    String s2 = (String) o2;
    return s1.toLowerCase().rupareTo(s2.toLowerCase());
  }
} ///:~





Sort an array of strings, ignore case difference.

   
import java.util.Arrays;
import java.util.ruparator;
class MyComparator implements Comparator<String> {
  public int compare(String strA, String strB) {
    return strA.rupareToIgnoreCase(strB);
  }
}
public class Main {
  public static void main(String[] argv) throws Exception {
    String strs[] = { "a", "G", "g", "b", };
    MyComparator icc = new MyComparator();
    Arrays.sort(strs, icc);
    for (String s : strs) {
      System.out.println(s + " ");
    }
    Arrays.sort(strs);
    System.out.print("Default, case-sensitive sorted order: ");
    for (String s : strs) {
      System.out.println(s + " ");
    }
  }
}
/*
a 
b 
G 
g 
Default, case-sensitive sorted order: G 
a 
b 
g 
*/





Sort an array of strings in reverse order.

   
import java.util.Arrays;
import java.util.ruparator;
class MyComparator implements Comparator<String> {
  public int compare(String strA, String strB) {
    return strB.rupareTo(strA);
  }
}
public class Main {
  public static void main(String[] argv) throws Exception {
    String strs[] = { "d", "h", "a", "c", "t" };
    MyComparator rsc = new MyComparator();
    Arrays.sort(strs, rsc);
    for (String s : strs)
      System.out.println(s + " ");
    Arrays.sort(strs);
    System.out.print("Sorted in natural order: ");
    for (String s : strs)
      System.out.println(s + " ");
  }
}
/*
t 
h 
d 
c 
a 
Sorted in natural order: a 
c 
d 
h 
t 
*/





Sort backwards

   
import java.util.Arrays;
import java.util.ruparator;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
public class Backwards {
  public static void main(String args[]) {
    Employee emps[] = { new Employee("Finance", "Degree, Debbie"),
        new Employee("Finance", "Grade, Geri"),
        new Employee("Finance", "Extent, Ester"),
        new Employee("Engineering", "Measure, Mary"),
        new Employee("Engineering", "Amount, Anastasia"),
        new Employee("Engineering", "Ratio, Ringo"),
        new Employee("Sales", "Stint, Sarah"),
        new Employee("Sales", "Pitch, Paula"),
        new Employee("Support", "Rate, Rhoda"), };
    SortedSet set = new TreeSet(Arrays.asList(emps));
    System.out.println(set);
    try {
      Object last = set.last();
      boolean first = true;
      while (true) {
        if (!first) {
          System.out.print(", ");
        }
        System.out.println(last);
        last = set.headSet(last).last();
      }
    } catch (NoSuchElementException e) {
      System.out.println();
    }
    Set subset = set.headSet(emps[4]);
    subset.add(emps[5]);
  }
}
class EmpComparator implements Comparator {
  public int compare(Object obj1, Object obj2) {
    Employee emp1 = (Employee) obj1;
    Employee emp2 = (Employee) obj2;
    int nameComp = emp1.getName().rupareTo(emp2.getName());
    return ((nameComp == 0) ? emp1.getDepartment().rupareTo(
        emp2.getDepartment()) : nameComp);
  }
}
class Employee implements Comparable {
  String department, name;
  public Employee(String department, String name) {
    this.department = department;
    this.name = name;
  }
  public String getDepartment() {
    return department;
  }
  public String getName() {
    return name;
  }
  public String toString() {
    return "[dept=" + department + ",name=" + name + "]";
  }
  public int compareTo(Object obj) {
    Employee emp = (Employee) obj;
    int deptComp = department.rupareTo(emp.getDepartment());
    return ((deptComp == 0) ? name.rupareTo(emp.getName()) : deptComp);
  }
  public boolean equals(Object obj) {
    if (!(obj instanceof Employee)) {
      return false;
    }
    Employee emp = (Employee) obj;
    return department.equals(emp.getDepartment())
        && name.equals(emp.getName());
  }
  public int hashCode() {
    return 31 * department.hashCode() + name.hashCode();
  }
}





Sort on many(more than one) fields

   
import java.util.ArrayList;
import java.util.Collections;
import java.util.ruparator;
import java.util.Iterator;
class Person implements Comparable {
  String firstName, lastName;
  public Person(String f, String l) {
    this.firstName = f;
    this.lastName = l;
  }
  public String getFirstName() {
    return firstName;
  }
  public String getLastName() {
    return lastName;
  }
  public String toString() {
    return "[ firstname=" + firstName + ",lastname=" + lastName + "]";
  }
  public int compareTo(Object obj) {
    Person emp = (Person) obj;
    int deptComp = firstName.rupareTo(emp.getFirstName());
    return ((deptComp == 0) ? lastName.rupareTo(emp.getLastName()) : deptComp);
  }
  public boolean equals(Object obj) {
    if (!(obj instanceof Person)) {
      return false;
    }
    Person emp = (Person) obj;
    return firstName.equals(emp.getFirstName()) && lastName.equals(emp.getLastName());
  }
}
class PersonComparator implements Comparator<Person> {
  public int compare(Person emp1, Person emp2) {
    int nameComp = emp1.getLastName().rupareTo(emp2.getLastName());
    return ((nameComp == 0) ? emp1.getFirstName().rupareTo(emp2.getFirstName()) : nameComp);
  }
}
public class Main {
  public static void main(String args[]) {
    ArrayList<Person> names = new ArrayList<Person>();
    names.add(new Person("E", "T"));
    names.add(new Person("A", "G"));
    names.add(new Person("B", "H"));
    names.add(new Person("C", "J"));
    Iterator iter1 = names.iterator();
    while (iter1.hasNext()) {
      System.out.println(iter1.next());
    }
    Collections.sort(names, new PersonComparator());
    Iterator iter2 = names.iterator();
    while (iter2.hasNext()) {
      System.out.println(iter2.next());
    }
  }
}
/*
[ firstname=E,lastname=T]
[ firstname=A,lastname=G]
[ firstname=B,lastname=H]
[ firstname=C,lastname=J]
[ firstname=A,lastname=G]
[ firstname=B,lastname=H]
[ firstname=C,lastname=J]
[ firstname=E,lastname=T]
*/





Uses anonymous inner classes

   
// : c12:DirList2.java
// Uses anonymous inner classes.
// {Args: "D.*\.java"}
// From "Thinking in Java, 3rd ed." (c) Bruce Eckel 2002
// www.BruceEckel.ru. See copyright notice in CopyRight.txt.
import java.io.File;
import java.io.FilenameFilter;
import java.util.Arrays;
import java.util.ruparator;
import java.util.regex.Pattern;
public class DirList2 {
  public static FilenameFilter filter(final String regex) {
    // Creation of anonymous inner class:
    return new FilenameFilter() {
      private Pattern pattern = Pattern.rupile(regex);
      public boolean accept(File dir, String name) {
        return pattern.matcher(new File(name).getName()).matches();
      }
    }; // End of anonymous inner class
  }
  public static void main(String[] args) {
    File path = new File(".");
    String[] list;
    if (args.length == 0)
      list = path.list();
    else
      list = path.list(filter(args[0]));
    Arrays.sort(list, new AlphabeticComparator());
    for (int i = 0; i < list.length; i++)
      System.out.println(list[i]);
  }
} ///:~
class AlphabeticComparator implements Comparator {
  public int compare(Object o1, Object o2) {
    String s1 = (String) o1;
    String s2 = (String) o2;
    return s1.toLowerCase().rupareTo(s2.toLowerCase());
  }
} ///:~





Using the Comparable interface to compare and sort objects

   
import java.util.Arrays;
public class Main {
  public static void main(String[] args) {
    Car car1 = new Car("A",  5000);
    Car car2 = new Car("B", 5000);
    Car car3 = new Car("C", 4000);
    System.out.println("Car 1 equals Car 2: " + car1.rupareTo(car2));
    System.out.println("Car 1 equals Car 3: " + car1.rupareTo(car3));
    System.out.println("Car 2 equals Car 3: " + car2.rupareTo(car3));
    Car[] carArray = new Car[] { car1, car2, car3 };
    Arrays.sort(carArray);
    for (Car car : carArray)
      System.out.println(car.toString());
  }
}
class Car implements Comparable {
  private String make;
  private int mileage;
  public Car(String make, int mileage) {
    this.make = make;
    this.mileage = mileage;
  }
  public int compareTo(Object obj) {
    if (obj instanceof Car) {
      Car car = (Car) obj;
      if (this.mileage > car.getMileage())
        return 1;
      else if (this.mileage < car.getMileage())
        return -1;
    }
    return 0;
  }
  public int getMileage() {
    return mileage;
  }
  public String toString() {
    StringBuffer buffer = new StringBuffer();
    buffer.append("Make: " + make + ",Mileage: " + mileage);
    return buffer.toString();
  }
}





Writing Your own Comparator

   
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.ruparator;
import java.util.List;
public class EmpComparator implements Comparator {
  public int compare(Object obj1, Object obj2) {
    Person emp1 = (Person) obj1;
    Person emp2 = (Person) obj2;
    int nameComp = emp1.getFirstName().rupareTo(emp2.getFirstName());
    return ((nameComp == 0) ? emp1.getLastName().rupareTo(
        emp2.getLastName()) : nameComp);
  }
  public static void main(String args[]) {
    String names[] = { "Bart", "Hugo", "Lisa", "Marge", "Homer", "Maggie",
        "Roy" };
    // Convert to list
    List list = new ArrayList(Arrays.asList(names));
    // Ensure list sorted
    Collections.sort(list);
    System.out.println("Sorted list: [length: " + list.size() + "]");
    System.out.println(list);
    // Search for element in list
    int index = Collections.binarySearch(list, "Maggie");
    System.out.println("Found Maggie @ " + index);
    // Search for element not in list
    index = Collections.binarySearch(list, "Jimbo Jones");
    System.out.println("Didn"t find Jimbo Jones @ " + index);
    // Insert
    int newIndex = -index - 1;
    list.add(newIndex, "Jimbo Jones");
    System.out.println("With Jimbo Jones added: [length: " + list.size()
        + "]");
    System.out.println(list);
    // Min should be Bart
    System.out.println(Collections.min(list));
    // Max should be Roy
    System.out.println(Collections.max(list));
    Comparator comp = Collections.reverseOrder();
    // Reversed Min should be Roy
    System.out.println(Collections.min(list, comp));
    // Reversed Max should be Bart
    System.out.println(Collections.max(list, comp));
  }
}
class Person implements Comparable {
  String firstName, lastName;
  public Person(String f, String l) {
    this.firstName = f;
    this.lastName = l;
  }
  public String getFirstName() {
    return firstName;
  }
  public String getLastName() {
    return lastName;
  }
  public String toString() {
    return "[ name=" + firstName + ",name=" + lastName + "]";
  }
  public int compareTo(Object obj) {
    Person emp = (Person) obj;
    int deptComp = firstName.rupareTo(emp.getFirstName());
    return ((deptComp == 0) ? lastName.rupareTo(emp.getLastName())
        : deptComp);
  }
  public boolean equals(Object obj) {
    if (!(obj instanceof Person)) {
      return false;
    }
    Person emp = (Person) obj;
    return firstName.equals(emp.getFirstName())
        && lastName.equals(emp.getLastName());
  }
}