Reputation: 457
I'm new to Java and learning about Collections. As an exercise, I'm trying to sort a SortedMap using a custom Comparator. I'd like to be able sort the students SortedMap by average of grades in descending order.
SortedMap <String, Student> students = new TreeMap <String, Student> ();
public class Student {
private String name;
private List<Integer> marks = new ArrayList<Integer>();
public Student(String n) {
this.name = n;
}
public String getName() {
return this.name;
}
public Double getAvg() {
return this.getStats()
.getAverage();
}
public void addMark(Integer mark) {
this.marks.add(mark);
}
public DoubleSummaryStatistics getStats() {
return this.marks.stream()
.mapToDouble(mark -> mark)
.summaryStatistics();
}
@Override
public String toString() {
return this.name + " " + getStats().getCount() + " " + getStats().getAverage();
}
}
I was able to figure out how to build a custom comparator that returns a set:
SortedSet<Map.Entry<String, Student>> meritSet = new TreeSet<Map.Entry<String, Student>>(
new Comparator<Map.Entry<String, Student>>() {
@Override
public int compare(Map.Entry<String, Student> s1,
Map.Entry<String, Student> s2) {
Double s1Avg = students.get(s1.getKey()).getStats().getAverage();
Double s2Avg = students.get(s2.getKey()).getStats().getAverage();
return s1Avg.compareTo(s2Avg);
}
}
);
meritSet.addAll(students.entrySet());
How would I code a custom comparator that returns a SortedMap and not a SortedSet?
Upvotes: 1
Views: 180
Reputation: 18568
What you can do in order to use a TreeMap
which implements SortedMap
is make the Student
implement Comparable
like this:
public class Student implements Comparable<Student> {
/*
* nearly the entire class stays untouched,
* except from the class declaration and the additional method below
*/
@Override
public int compareTo(Student o) {
return this.getAvg().compareTo(o.getAvg());
}
// you could and probably should implement equals(Student o) and hashCode() as well
}
This will automatically sort the entries in a TreeMap<Student, SomethingElse>
by the values of the method getAvg()
(using the method compareTo
of Double
).
The
TreeMap
will be sorted by its keys... So consider using aMap
that takesStudent
s as keys.
If you now want to have a SortedSet
, like a TreeSet<Student>
it will be sorted accordingly, just by having implemented Comparable<Student>
.
Upvotes: 1
Reputation: 2828
What you want to do is sort a Map
based on it's values.
This is however not something that can be achieved with a SortedMap
.
A Map that further provides a total ordering on its keys.
If you just want to store them sorted in a Map
, without requiring the Map
to still be sorted when you would add new values, you could store all entries in a LinkedHashMap
:
Map<String, Studen> meritMap = meritSet.stream()
.collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a, LinkedHashMap::new));
This won't give you a SortedMap
though, but the Map
will be sorted.
Upvotes: 3