I often get into situation when I need to sort a Map on values. Maps are not meant for that in JDK and I decided not to use Guava (seems like this stuff is one liner but I didn't quite get it) nor Apache Commons, so I do it this way. Btw this is a very popular question, but most of the answers are wrong in one way or another.
Map<String, Long> map = new HashMap<String, Long>();
// populate
List<Map.Entry<String, Long>> list = new LinkedList<Map.Entry<String,Long>>();
for (Map.Entry<String, Long> entry : map.entrySet()) {
list.add(entry);
}
Collections.sort(list, new MapComparable());
LinkedHashMap<String, Long> linkedMap = new LinkedHashMap<String, Long>();
for (Map.Entry<String, Long> entry : list) {
linkedMap.put(entry.getKey(), entry.getValue());
}
}
public static class MapComparable implements Comparator<Map.Entry<String, Long>>{
public int compare(Entry<String, Long> e1, Entry<String, Long> e2) {
return (e1.getValue()<e2.getValue() ? -1 : (e1.getValue()==e2.getValue() ? 0 : 1));
}
}
My question is, is there a better way of getting the EntrySet to / from Collection ? It doesn't look good.
And is this reliable ?
What I think is a very slight improvement to your method is:
Queue queue = new PriorityQueue( map.size(), new MapComparable() );
queue.addAll( map.entrySet() );
LinkedHashMap<String, Long> linkedMap = new LinkedHashMap<String, Long>();
for (Map.Entry<String, Long> entry; (entry = queue.poll())!=null;) {
linkedMap.put(entry.getKey(), entry.getValue());
}
In other words, do the sorting with a datastructure designed for sorting.
As a general note, code like
for (Map.Entry<String, Long> entry : map.entrySet()) {
list.add(entry);
}
Can be shortened to:
list.addAll( map.entrySet() );
whenever you're dealing with Collection
s.
Also I think this:
public int compare(Entry<String, Long> e1, Entry<String, Long> e2) {
return e1.getValue().compareTo(e2.getValue());
}
is cleaner.