001 package edu.nrao.sss.sort; 002 003 import java.util.ArrayList; 004 import java.util.Comparator; 005 import java.util.List; 006 007 /** 008 * A sort key for {@link Enum enumerations}. 009 * <p/> 010 * The most common way to extend this class is to subclass it into a class 011 * that also implements {@link Comparator}. The main job of the subclass 012 * is to provide the integers to this parent class. Example: 013 * <pre> 014 * /** 015 * * Sorts players according to the hand with which they bat. 016 * */ 017 * public class PlayerBattingHandKey extends EnumSortKey<Handedness> 018 * implements Comparator<Player> 019 * { 020 * public int compare(Player p1, Player p2) 021 * { 022 * return compareObjects(p1.getBattingHand() 023 * p2.getBattingHand()); 024 * } 025 * }</pre> 026 * <p> 027 * Clients of the example <tt>PlayerBattingHandKey</tt> class are able to 028 * configure that comparator via the {@link #setOrder(SortOrder)} method, 029 * something they cannot do with the plain <tt>Comparator</tt> interface. 030 * They may then place instances of this class in a 031 * {@link CompoundComparator}.</p> 032 * <p> 033 * <b>Version Info:</b> 034 * <table style="margin-left:2em"> 035 * <tr><td>$Revision: 593 $</td></tr> 036 * <tr><td>$Date: 2007-05-07 15:54:14 -0600 (Mon, 07 May 2007) $</td></tr> 037 * <tr><td>$Author: dharland $</td></tr> 038 * </table></p> 039 * 040 * @author David M. Harland 041 * @since 2007-05-03 042 */ 043 044 public abstract class EnumSortKey<E extends Enum<E>> 045 extends SortKey<E> 046 { 047 private List<E> customOrder; 048 049 /** Helps create a new instance. */ 050 protected EnumSortKey() 051 { 052 super(); 053 054 customOrder = new ArrayList<E>(); 055 } 056 057 /** 058 * Sets the ordering for this sort key. 059 * <p> 060 * The list of elements should contain no more than one occurrence of a 061 * given element. Additional occurrences after the first are permitted 062 * but will be ignored. The list need not have an occurrence of every 063 * element of the enumeration. Any elements not present in the list will 064 * be deemed to be greater than an element that is in the list. 065 * A comparison between two unlisted elements will result in a tie.</p> 066 * <p> 067 * The custom ordering provided here will be used only when the 068 * sort order is {@link #setOrder(SortOrder) set} to 069 * {@link SortOrder#CUSTOM}.</p> 070 * <p> 071 * This method will not save a reference to {@code ordering}, so any changes 072 * made to the list after this method is called will not be reflected in 073 * this object.</p> 074 * 075 * @param ordering a list containing elements of an enumeration in the order 076 * in which this key should sort them. 077 */ 078 public void setCustomOrder(List<E> ordering) 079 { 080 customOrder.clear(); 081 customOrder.addAll(ordering); 082 } 083 084 /** 085 * Returns a number less than zero, zero, or greater than zero 086 * as <tt>o1</tt> is before, coincident with, or after <tt>o2</tt> 087 * when sorted in according to t he given sort order. 088 * <p/> 089 * This method is called by compareObjects(T o1, T o2). 090 */ 091 @Override 092 protected int compareObjects(E o1, E o2, SortOrder ordering) 093 { 094 switch (ordering) 095 { 096 case AS_IS: return 0; 097 098 case NATURAL: return compareNatural(o1, o2); 099 100 case ASCENDING: return compareAscending(o1, o2); 101 102 case DESCENDING: return -compareAscending(o1, o2); 103 104 case CUSTOM: return compareCustom(o1, o2); 105 106 default: 107 throw new IllegalStateException( 108 "Unrecognized or disallowed SortOrder "+ 109 ordering + " found in comparObjects(...)"); 110 } 111 } 112 113 /** 114 * Uses the natural ordering of {@code E}. 115 */ 116 protected int compareNatural(E o1, E o2) 117 { 118 return o1.compareTo(o2); 119 } 120 121 /** 122 * Uses the natural ordering of {@code E}. 123 */ 124 protected int compareAscending(E o1, E o2) 125 { 126 return compareNatural(o1, o2); 127 } 128 129 /** 130 * Uses a client-specified ordering 131 */ 132 protected int compareCustom(E o1, E o2) 133 { 134 int comparison; 135 136 int pos1 = customOrder.indexOf(o1); 137 int pos2 = customOrder.indexOf(o2); 138 139 //If both are in custom list, return difference in positions 140 if (pos1 >= 0 && pos2 >= 0) 141 { 142 comparison = pos1 - pos2; 143 } 144 //If neither is in list, keep their current ordering 145 else if (pos1 < 0 && pos2 < 0) 146 { 147 comparison = 0; 148 } 149 //If exactly one is not in list, push unlisted element to end 150 else 151 { 152 if (pos1 < 0) 153 comparison = +1; 154 else //(pos2 < 0) 155 comparison = -1; 156 } 157 158 return comparison; 159 } 160 }