简体   繁体   中英

How to improve sorting on values of a Map via Collections

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?

You could maintain a dual data structure, one set as a Map that provides string -> long conversions, and the other as a List or similar structure that provides ordered conversions, with an overall structure to maintain both together.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM