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

    Threaded Messages (11)

  2. Something like this, maybe?

    Map someMap= new LinkedHashMap();

    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);

    LinkedHashMap someMap = new LinkedHashMap();
    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;
    }
  4. How about without LinkedHashMap[ Go to top ]

    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);
        list.add(customEntry);
      }
      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);
        list.add(customEntry);
      }
      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 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. 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. Thank You, Artem & Anders, That was of great help.

    Regards,
    Vishal