patternjavaMinor
Enumerated rank comparator utility class
Viewed 0 times
rankenumeratedutilityclasscomparator
Problem
A common task I often face is ordering a collection of items according to some predefined model, typically expressed as an ordered list of ranks. For example, credit agencies might rate financial products as:
I often need a way of ordering a collection of objects by such ratings.
I could try to hack something together roughly based on the alphabet,
but it seems more extensible to take a model list of the defined order, and use that in the comparison: when given two ratings, find their indexes in the model list, and use the indexes to decide the ordering.
To make this a reusable general purpose utility, I came up with this:
To illustrate the usage with an example, consider this enumeration of
```
enum Rating {
AAA_PLUS("AAA+"),
AAA("AAA"),
AAA_MINUS("AAA-"),
AA_PLUS("AA+"),
AA(
- AAA (excellent investment)
- AA (very good investment)
- B (not so good investment)
- BB (poor investment)
- BBB (why are we investing in this steamy pile of garbage?)
- NR (not rated / unknown)
I often need a way of ordering a collection of objects by such ratings.
I could try to hack something together roughly based on the alphabet,
but it seems more extensible to take a model list of the defined order, and use that in the comparison: when given two ratings, find their indexes in the model list, and use the indexes to decide the ordering.
To make this a reusable general purpose utility, I came up with this:
class EnumeratedRankComparator implements Comparator {
private final Map itemsToIndex;
private EnumeratedRankComparator(List items) {
itemsToIndex = new HashMap<>(items.size());
int index = 0;
for (T item : items) {
if (itemsToIndex.containsKey(item)) {
throw new IllegalArgumentException("Inconsistent ranks: there should be no duplicates");
}
itemsToIndex.put(item, ++index);
}
}
public static EnumeratedRankComparator fromLowToHigh(List items) {
return new EnumeratedRankComparator<>(items);
}
public static EnumeratedRankComparator fromHighToLow(List items) {
List copy = new ArrayList<>(items);
Collections.reverse(copy);
return new EnumeratedRankComparator<>(copy);
}
@Override
public int compare(T o1, T o2) {
return Integer.compare(itemsToIndex.get(o1), itemsToIndex.get(o2));
}
}To illustrate the usage with an example, consider this enumeration of
Rating values:```
enum Rating {
AAA_PLUS("AAA+"),
AAA("AAA"),
AAA_MINUS("AAA-"),
AA_PLUS("AA+"),
AA(
Solution
There are two major sections to your question, the first has a general purpose comparator setup, the second has a specific rankings system. The Rankings system is the one that concerns me most.....
... it's an enum. Enums are naturally comparable, and sort in the same order of their declaration. Your entire use case in the second set can be handled (in Java 8) with:
In earlier versions:
Sorting of enums in their natural order should not be a problem.
As for the general case, I think your system is OK. I can't think of a better way to do it... the Map seems expensive, but it is small, and limited in size, and should be fine. For small input Lists (less than 5 or so), I would consider a simple Array containing the members, in order, and loop them checking each one.... and returning the index of a match. Benchmarking may prove enlightening.
... it's an enum. Enums are naturally comparable, and sort in the same order of their declaration. Your entire use case in the second set can be handled (in Java 8) with:
private final Comparator comparator = Comparator.naturalOrder();In earlier versions:
public class EnumComparator implements Comparator {
@Override
public int compare(T e1, T e2) {
return e1.compareTo(e2);
}
};Sorting of enums in their natural order should not be a problem.
As for the general case, I think your system is OK. I can't think of a better way to do it... the Map seems expensive, but it is small, and limited in size, and should be fine. For small input Lists (less than 5 or so), I would consider a simple Array containing the members, in order, and loop them checking each one.... and returning the index of a match. Benchmarking may prove enlightening.
Code Snippets
private final Comparator<Rating> comparator = Comparator.naturalOrder();public class EnumComparator<T extends Enum> implements Comparator<T> {
@Override
public int compare(T e1, T e2) {
return e1.compareTo(e2);
}
};Context
StackExchange Code Review Q#83147, answer score: 7
Revisions (0)
No revisions yet.