Sorting HashMap based on its Values

## Discussions

### General J2EE: Sorting HashMap based on its Values

1. #### Sorting HashMap based on its Values (11 messages)

Hi,

Can someone suggest me or send a code snippet to sort the HashMap based on its values(not the keys), so that when I display, I get the values in some sorted manner.

Thanks & Regards,
Vishal

2. #### Sorting HashMap based on its Values[ Go to top ]

Something like this, maybe?

someMap.put("key1","c");
someMap.put("key2","a");
someMap.put("key3","b");

List mapKeys = new ArrayList(someMap.keySet());
List mapValues = new ArrayList(someMap.values());

someMap.clear();

TreeSet sortedSet = new TreeSet(mapValues);

Object[] sortedArray = sortedSet.toArray();

int size = sortedArray.length;

//a) Ascending sort

for (int i=0; i<size; i++)
{

//System.out.println(sortedArray[i]);

someMap.put(mapKeys.get(mapValues.indexOf(sortedArray[i])), sortedArray[i]);

}

System.out.println(someMap);

someMap.clear();

//b) Descending sort

for (int i=size; i>0;)
{

someMap.put(mapKeys.get(mapValues.indexOf(sortedArray[--i])), sortedArray[i]);

}

System.out.println(someMap);

Regards,

Artem D. Yegorov
http://www.activexml.org
3. #### Close, but throws out ties[ Go to top ]

That works if all the values are unique, which isn't true in my case. I ened up with the below. Maybe somebody can make it better, but it does deal with duplicate values.

public LinkedHashMap sortHashMapByValues(HashMap passedMap, boolean ascending) {

List mapKeys = new ArrayList(passedMap.keySet());
List mapValues = new ArrayList(passedMap.values());
Collections.sort(mapValues);
Collections.sort(mapKeys);

if (!ascending)
Collections.reverse(mapValues);

Iterator valueIt = mapValues.iterator();
while (valueIt.hasNext()) {
Object val = valueIt.next();
Iterator keyIt = mapKeys.iterator();
while (keyIt.hasNext()) {
Object key = keyIt.next();
if (passedMap.get(key).toString().equals(val.toString())) {
passedMap.remove(key);
mapKeys.remove(key);
someMap.put(key, val);
break;
}
}
}
return someMap;
}

Any ideas on how to do this without using a LinkedHashMap? We're still on 1.3 which doesn't support LinkedHashMap and I'm not going to get the web admins to upgrade us anytime soon.
5. #### Use TreeMap[ Go to top ]

I would look at the TreeMap that is available in 1.3 and look at implementing the comparable interfaces to the value objects or provide a comparator object. This should take care of all your probs.

http://java.sun.com/j2se/1.3/docs/api/java/util/TreeMap.html
6. #### Solution - Use a List[ Go to top ]

I had the same problem - could not sort a map based on values rather than keys. To solve this I simply created a list of objects, where each object wraps a Map.Entry and implements java.lang.Comparable.

Here's the class:
-----
import java.util.*;

public class CustomEntry implements Comparable{
private Map.Entry entry;

public CustomEntry(Map.Entry entry) {
this.entry = entry;
}

public Map.Entry getEntry() {
return this.entry;
}

public int compareTo(CombinationEntry anotherEntry) {
Integer thisIntegerVal = (Integer)(this.getEntry().getValue());
int thisVal = thisIntegerVal.intValue();
Integer anotherIntegerVal = (Integer)(anotherEntry.getEntry().getValue());
int anotherVal = anotherIntegerVal.intValue();
return (thisVal<anotherVal ? 1 : (thisVal==anotherVal ? 0 : -1));
}

public int compareTo(Object o) {
return compareTo((CombinationEntry)o);
}

}
-----

You first convert your map to a list of these custom entries (here's a method, which does this):
----------
public static List convertMapToList(Map map) {
List list = new ArrayList();
Set entrySet = map.entrySet();
Iterator iterator = entrySet.iterator();
while (iterator.hasNext()) {
Map.Entry entry = (Map.Entry)iterator.next();
CustomEntry customEntry = new CustomEntry(entry);
}
return list;
}

----------

Now you can sort the list produced from the above method by calling java.util.Collections.sort(List list).

Unfortunately, what you are left with is not a map anymore but a list pretending to be a map!
7. #### Correction[ Go to top ]

In my previous post there were 2 errors - CombinationEntry should be CustomEntry. Here is the corrected version of my message:
--------

I had the same problem - could not sort a map based on values rather than keys. To solve this I simply created a list of objects, where each object wraps a Map.Entry and implements java.lang.Comparable.

Here's the class:
-----
import java.util.*;

public class CustomEntry implements Comparable{
private Map.Entry entry;

public CustomEntry(Map.Entry entry) {
this.entry = entry;
}

public Map.Entry getEntry() {
return this.entry;
}

public int compareTo(CustomEntry anotherEntry) {
Integer thisIntegerVal = (Integer)(this.getEntry().getValue());
int thisVal = thisIntegerVal.intValue();
Integer anotherIntegerVal = (Integer)(anotherEntry.getEntry().getValue());
int anotherVal = anotherIntegerVal.intValue();
return (thisVal<anotherVal ? 1 : (thisVal==anotherVal ? 0 : -1));
}

public int compareTo(Object o) {
return compareTo((CustomEntry)o);
}

}
-----

You first convert your map to a list of these custom entries (here's a method, which does this):
----------
public static List convertMapToList(Map map) {
List list = new ArrayList();
Set entrySet = map.entrySet();
Iterator iterator = entrySet.iterator();
while (iterator.hasNext()) {
Map.Entry entry = (Map.Entry)iterator.next();
CustomEntry customEntry = new CustomEntry(entry);
}
return list;
}

----------

Now you can sort the list produced from the above method by calling java.util.Collections.sort(List list).

Unfortunately, what you are left with is not a map anymore but a list pretending to be a map!
8. #### Possible Enhancement[ Go to top ]

Along the same lines as Oluwafemi's. Using an annonymous inner class is a little cleaner perhaps.

----------------------------

Map<String, Integer> map = new HashMap<String, Integer>();

// --- Put entries into map here ---

// Get a list of the entries in the map
List<Map.Entry<String, Integer>> list = new Vector<Map.Entry<String, Integer>>(map.entrySet());

// Sort the list using an annonymous inner class implementing Comparator for the compare method
java.util.Collections.sort(list, new Comparator<Map.Entry<String, Integer>>(){
public int compare(Map.Entry<String, Integer> entry, Map.Entry<String, Integer> entry1)
{
// Return 0 for a match, -1 for less than and +1 for more then
return (entry.getValue().equals(entry1.getValue()) ? 0 : (entry.getValue() > entry1.getValue() ? 1 : -1));
}
});

// Clear the map
map.clear();

// Copy back the entries now in order
for (Map.Entry<String, Integer> entry: list)
{
map.put(entry.getKey(), entry.getValue());
}
9. #### And Another Thing[ Go to top ]

Not sure that it's good practise to consider a Map as having an ordering at all.
10. #### How to count redundant values of HashMap entrysets?[ Go to top ]

How can I count this hashmap? I would like to display:
1. All champions who won more than once - show the number that they won. eg. Uraguay: 2
2. I would like to display the country who won most World Cup: say Brazil: 5

The above should be all related to counting utility. Can someone help? Thx much.

import java.util.Map;
import java.util.HashMap;

public class FIFAFinalMap {

public static void main(String[] args) {

Map<String, String> map = new HashMap<String, String>();
// add world cup year and champions
map.put("1930", "Uruguay");
map.put("1934", "Italy");
map.put("1938", "Italy");
map.put("1950", "Uruguay");
map.put("1954", "West Germany");
map.put("1958", "Brazil");
map.put("1962", "Brazil");
map.put("1966", "England");
map.put("1970", "Brazil");
map.put("1974", "West Germany");
map.put("1978", "Argentina");
map.put("1982", "Italy");
map.put("1986", "Argentina");
map.put("1990", "West Germany");
map.put("1994", "Brazil");
map.put("1998", "France");
map.put("2002", "Brazil");
map.put("2006", "Italy");
map.put("2010", "Spain");

// display map
System.out.println(map);

// for loop the map
for (Map.Entry<String, String> me : map.entrySet()) {
String year = me.getKey();
String champion = me.getValue();
System.out.println(year + ": " + champion);
}

System.out.println("\nShall we bow to octopus Paul? :)");

// sort by year and count???
}
}

11. #### Re: Sorting Maps based on its values[ Go to top ]

If it doesn't have to be a 'Hash' map and if you're allowed to leverage some nice open source you may want to consider automaticly sorted maps like the TreeBidiMap (a SortedBidiMap) of Jakarta Commons Collections. Direct link to Javadoc
http://jakarta.apache.org/commons/collections/apidocs-COLLECTIONS_3_1/org/apache/commons/collections/bidimap/TreeBidiMap.html
12. #### Re: Sorting Maps based on its values[ Go to top ]

Thank You, Artem & Anders, That was of great help.

Regards,
Vishal