11

Possible Duplicate:
How to sort a Map<Key, Value> on the values in Java?

I have a HashMap of the type:

HashMap<String, Integer> h = new HashMap<String, Integer>();

The HashMap contains a list of Strings and the Integer is a counter for the number of times that String has been found. What I would like to be able to do is sort the HashMap based on the Integers, then on the alphabetical order of the Strings.

At the moment I am keeping a record of the largest occurrence of a word (variable named max) and displaying the values as follows:

public void print(){
    while(max > 0){
       for (String key : h.keySet()){
           if(h.get(key) == max){
               System.out.println(key + " " + h.get(key));
           }
       }
       max--;
    }
}

Which doesn't sort the values alphabetically, also it accesses the HashMap max*h(size) times.

What is the better solution?

1
  • @krock good find. Yep, exact same question. Commented Jun 19, 2010 at 3:14

4 Answers 4

17

Here's a Comparator that sorts Map.Entry objects with Comparable keys and values:

public class ValueThenKeyComparator<K extends Comparable<? super K>,
                                    V extends Comparable<? super V>>
    implements Comparator<Map.Entry<K, V>> {

    public int compare(Map.Entry<K, V> a, Map.Entry<K, V> b) {
        int cmp1 = a.getValue().compareTo(b.getValue());
        if (cmp1 != 0) {
            return cmp1;
        } else {
            return a.getKey().compareTo(b.getKey());
        }
    }

}

You'd put all of the map entries into a list and then sort that:

List<Map.Entry<String, Integer>> list = new ArrayList<Map.Entry<String, Integer>>(h.entrySet());
Collections.sort(list, new ValueThenKeyComparator<String, Integer>());
Sign up to request clarification or add additional context in comments.

1 Comment

Almost, I guess because because this way words with fewer occurrence come first..
4

Look at Google Guava libraries. It has a Multiset which does the calculation for you and then you have Ordering class that simplifies sorting.

All you need to do is to populate Multiset with your strings. It will maintain the frequency for you. Then you can sort on those strings using Ordering.

Comments

3

Probably not the most elegant solution, but how about this?

//TreeSet with reversed natural ordering (big integers first)
Map<Integer, Set<String>> h = 
     new TreeMap<Integer, Set<String>>(Collections.reverseOrder());
//and use TreeSet for the set...
// ...    
// 
for(Map.Entry<Integer,Set<String>> entry : h.entrySet()){
    for(String str : entry.getValue()){
        System.out.println(str + " has occured " + entry.getKey() + " times.");
    }
}

2 Comments

-1 * o1.compareTo(o2) is flawed. Consider the case where compareTo returns Integer.MIN_VALUE.
Actually I shouldn't have written my own code for reversing the natural order :P Substituting with the Collections.reverseOrder() method..
-1

you can use SortedMap interface to sort your HashMap. It's very easy - Automatic sorting. Refer to http://java.sun.com/j2se/1.4.2/docs/api/java/util/SortedMap.html. I didn't include any code here, but if you need, just add a comment. I'll give you a sample code.

2 Comments

-1, SortedMap sorts by key, rather than by value
A map that further guarantees that it will be in ascending key order, sorted according to the natural ordering of its keys (see the Comparable interface), or by a comparator provided at sorted map creation time

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.