views:

299

answers:

4

I want my hash to sort in descending order according to the values. How do I do that in Java?

+2  A: 

Here's an easy way to do it. It involves writing your own class that implements Comparator and using it to sort your map by value.

For an extensive list of alternative approaches, some of which don't use comparators, it's worth to check out the answers to this SO question.

luvieere
I'd like to see your own example, because it actually involves a bit more work than letting the value object implement comparator.
BalusC
As I've pointed out, it's a duplicate, so you'll find a lot of examples in the answers to the question I've linked to.
luvieere
Right, but `Map` itself do nothing with `Comparator` (or `Comparable` as you seem to mean) in the entry **values**, while your first statement seem to insinuate that. Normally only entry **keys** will be sorted. To sort values, you need to do more work than just implementing `Comparator`.
BalusC
The article at the first link already explains the default behavior and what is being done to obtain the desired by-value sorting instead. I'm not implying that this sort would be persistent, or robust to new insertions, but it is a way to **sort** a map by value, not to obtain a map that sorts its entries by value upon insertion.
luvieere
A: 

Use Collections.reverseOrder().

starblue
I think the difficult bit with the question is "according to the values", not "descending"
Buhb
+1  A: 

A HashMap (and its legacy predecesor Hashtable) is by nature unordered. Even if you sort it, it will remain unordered. If you want to maintain insertion order, then use LinkedHashMap instead. If you want an automatic sort on keys, regardless of insertion order, then use SortedMap instead.

If you want to sort a Map on values, then you basically need to put the key/value pairs in another kind of a sortable data structure, e.g. List<Entry<K, V>>, then sort it using Collections#sort() with help of a Compatator<Entry<K, V>> and finally repopulate a LinkedHashMap with it (not a HashMap or you will lose the ordering again).

Here's a basic example (leaving obvious runtime exception handling aside):

// Prepare.
Map<String, String> map = new HashMap<String, String>();
map.put("foo", "bar");
map.put("bar", "waa");
map.put("waa", "foo");
System.out.println(map); // My JVM shows {waa=foo, foo=bar, bar=waa}

// Get entries and sort them.
List<Entry<String, String>> entries = new ArrayList<Entry<String, String>>(map.entrySet());
Collections.sort(entries, new Comparator<Entry<String, String>>() {
    public int compare(Entry<String, String> e1, Entry<String, String> e2) {
        return e1.getValue().compareTo(e2.getValue());
    }
});

// Put entries back in an ordered map.
Map<String, String> orderedMap = new LinkedHashMap<String, String>();
for (Entry<String, String> entry : entries) {
    orderedMap.put(entry.getKey(), entry.getValue());
}

System.out.println(orderedMap); // {foo=bar, waa=foo, bar=waa}

To sort it descencing, use the following Comparator. Basically just swap the entries to compare:

Collections.sort(entries, new Comparator<Entry<String, String>>() {
    public int compare(Entry<String, String> e1, Entry<String, String> e2) {
        return e2.getValue().compareTo(e1.getValue()); // Sorts descending.
    }
});
BalusC
A: 

Here is how I do it:

public static <K, V extends Comparable<V>> Map<K, V> sortByValues(final Map<K, V> map) {
Comparator<K> valueComparator =  new Comparator<K>() {
    public int compare(K k1, K k2) {
        int compare = map.get(k2).compareTo(map.get(k1));
        if (compare == 0) return 1;
        else return compare;
    }
};
Map<K, V> sortedByValues = new TreeMap<K, V>(valueComparator);
sortedByValues.putAll(map);
return sortedByValues;

}

Anthony