I am trying to create a sorted map using TreeMap<String, Integer>
from an existing map in java.
Entries should be sorted based on value, so I created a custom Comparator
.
class ValueComparator implements Comparator<String> {
Map<String, Integer> base;
ValueComparator(Map<String, Integer> base) {
this.base = base;
}
@Override
public int compare(String o1, String o2) {
return base.get(o2).compareTo(base.get(o1));
}
}
class Test {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("a", 100);
map.put("b", 100);
map.put("c", 200);
map.put("d", 300);
map.put("e", 400);
SortedMap<String, Integer> sortedMap = new TreeMap<>(new ValueComparator(map));
sortedMap.putAll(map);
System.out.println(map);
System.out.println(sortedMap);
}
}
Output
{a=100, b=100, c=200, d=300, e=400}
{e=400, d=300, c=200, a=100}
As you can see, my sortedMap
has removed one key having the same value. Can someone explain this? And how can we fix this?
CodePudding user response:
According to the Comparator
you've provided, Strings "a"
and "b"
are duplicates because both of them are associated with value of 100
. Hence, one or the other has to be rejected.
Note that base.get(o2).compareTo(base.get(o1))
would raise a NullPointerException
if either o1
or o2
are not present in the base
map.
Something along these lines would be safer:
Objects.compare(
base.get(o2), base.get(o1),
Comparator.nullsFirst(Comparator.naturalOrder())
);
CodePudding user response:
You are missing the ordinal for dupes. Use it like this:
public int compare(String o1, String o2) {
int val = base.get(o2).compareTo(base.get(o1));
return val == 0 ? o1.compareTo(o2) : val;
}