Search code examples
javagenericscomparatorcomparable

Java : How to sort values of a HashMap with generic Key and Value?


I have a TreeMap that i need to Sort-By-Values. I am able sort the Map if the values are Integer type.

public class MapSorting {

    public static Map<String, Integer> sortByValues(Map<String, Integer> tempMap) {

        ValueComparator bvc = new ValueComparator(tempMap);
        Map<String, Integer> sortedMap = new TreeMap<String, Integer>(bvc);
        sortedMap.putAll(tempMap);
        return sortedMap;

    }
}


class ValueComparator implements Comparator<String> {

        Map<String, Integer> base;

        public ValueComparator(Map<String, Integer> base) {
            this.base = base;
        }

        public int compare(String a, String b) {
            if (base.get(a) >= base.get(b)) {
                return -1;
            } else {
                return 1;
            }
        }
    }

But how do i make the method generic?? I want to be able to send Map with Key and Value of any type to this method.

I want to return a TreeMap that is sorted based on values.

Can anyone please help?


Solution

  • Note : A TreeMap is intended to be sorted by key, not by value. That makes me think that you should use another data structure to store your result : e.g. List<Entry<K, V>>.

    Note : I highly discourage to use this piece of code because I think it is an anti-pattern. I did it only to show how it would be possible.

    That said, I made it like this (need at least Java 8 or adapt the code) :

    public static <K, V extends Comparable> Map<K, V> sortByValues(Map<K, V> tempMap) {
      TreeMap<K, V> map = new TreeMap<>(buildComparator(tempMap));
      map.putAll(tempMap);
      return map;
    }
    
    public static <K, V extends Comparable> Comparator<? super K> buildComparator(final Map<K, V> tempMap) {
      return (o1, o2) -> tempMap.get(o1).compareTo(tempMap.get(o2));
    }
    

    Test :

    Map<Integer, String> map = new HashMap<>();
    map.put(1, "B");
    map.put(2, "C");
    map.put(3, "A");
    
    for(Map.Entry<Integer, String> entry : sortByValues(map).entrySet()) {
      System.out.println(entry.getKey()+" : "+ entry.getValue());
    }
    

    Output :

    3 : A
    1 : B
    2 : C
    

    Note : I dit not handle null cases because it is not important for this explanation.