I have an object which has a name and a score. I would like to sort a collection of such objects so that they are grouped by name and sorted by maximum score in each group (and
Foreach over the collection, and put the objects into a Map
, keyed by name, where the SortedSet is a TreeSet with a custom comparator that compares by score.
Then foreach over the map's values() collection, and put the groups into a SortedSet
, with a second custom comparator that compares SortedSets according to their largest element. Actually, instead of foreaching, you can simply use addAll().
Here's the code:
public class SortThings {
static class Thing {
public final String name;
public final int score;
public Thing(String name, int score) {
this.name = name;
this.score = score;
}
@Override
public String toString() {
return "(" + name + ", " + score + ")";
}
}
public static void main(String[] args) {
Collection things = Arrays.asList(
new Thing("a", 3),
new Thing("a", 9),
new Thing("b", 7),
new Thing("b", 10),
new Thing("c", 8),
new Thing("c", 3)
);
SortedSet> sortedGroups = sortThings(things);
System.out.println(sortedGroups);
}
private static SortedSet> sortThings(Collection things) {
final Comparator compareThings = new Comparator() {
public int compare(Thing a, Thing b) {
Integer aScore = a.score;
Integer bScore = b.score;
return aScore.compareTo(bScore);
}
};
// first pass
Map> groups = new HashMap>();
for (Thing obj: things) {
SortedSet group = groups.get(obj.name);
if (group == null) {
group = new TreeSet(compareThings);
groups.put(obj.name, group);
}
group.add(obj);
}
// second pass
SortedSet> sortedGroups = new TreeSet>(new Comparator>() {
public int compare(SortedSet a, SortedSet b) {
return compareThings.compare(a.last(), b.last());
}
});
sortedGroups.addAll(groups.values());
return sortedGroups;
}
}
Note that the output is in smallest-to-largest order. That's the natural order with Java's collections; it would be trivial to modify this to sort the other way if that's what you need.