39

What I want to do is sort a map by value. I went over many questions that are available on the stackoverflow site and found out following solution that does what I want but missing a small thing.

Link1: Sorting Map

But the issue I am running into is that by default this is sorted by ascending order by value. I want to order it by descending order:

So what I did was I created a class that implements a comparator

class MyComparator implements Comparator {
    Map map;
    public MyComparator(Map map) {
        this.map = map;
    }
    public int compare(Object o1, Object o2) {
        return ((Integer) map.get(o2)).compareTo((Integer) map.get(o1));
    }
}

And then I pass my map to the treemap,

MyComparator comp = new MyComparator(myMap);
Map<String, Integer> newMap = new TreeMap(comp);
newMap.putAll(myMap);

This seems like bad approach because I feel this is inefficient. Is there a way to change the solution in the link to do ordering on descending order by default.

Community
  • 1
  • 1
add-semi-colons
  • 18,094
  • 55
  • 145
  • 232
  • 3
    You'd be surprised by what is and is not inefficient. You should run some tests... make a map of 50,000 random Integers and sort it this way, see how long it actually takes. (And do that 100 times or more, so you get a good average.) Try not to go with what you "feel" is inefficient. – dcsohl Sep 20 '13 at 18:15
  • 3
    If you actually read the comments in the linked answer, you'll discover that the technique you're using is actually a _really bad idea_. http://stackoverflow.com/a/2581754/869736 is the only answer to that question that really works in general. – Louis Wasserman Sep 20 '13 at 18:40

5 Answers5

135

You should use new TreeMap<>(Collections.reverseOrder());.

Map<String, Integer> newMap = new TreeMap<>(Collections.reverseOrder());
newMap.putAll(myMap);

or to reverse an existing comparator like the value-comparator Collections.reverseOrder(comparator). It works like your approach swapping the two objects before invoking compare/compareTo.

Naman
  • 27,789
  • 26
  • 218
  • 353
Holger
  • 285,553
  • 42
  • 434
  • 765
7
    TreeMap<Long,String> treeMap = new TreeMap<Long,String>();

    NavigableMap <Long, String> nmap = treeMap.descendingMap();

    Set<Long, String> set = nmap.entrySet();

    Iterator<Long, String> iterator = set.iterator();

now u can iterate over iterator and extract the value using iterator.hasNext() and iterator.next() methods ......

Nilesh Jadav
  • 890
  • 9
  • 8
4

This will work :

      TreeMap<Integer, Integer> reverseInteger=new TreeMap<>(new Comparator<Integer>() {

        @Override
        public int compare(Integer o1, Integer o2) {
            return o2>o1?1:o2==o1?0:-1;
        }
    });
Farman
  • 66
  • 1
2

You could simply invert the return value of your compare method by adding a minus sign at the beginning:

return -((Integer) map.get(o2)).compareTo((Integer) map.get(o1));
OCarneiro
  • 327
  • 3
  • 6
  • 1
    Very bad idea. If `compareTo` returns `Integer.MIN_VALUE` your code breaks. Swapping `o1` and `o2` *as already done in this code* does the job better. – Holger Sep 20 '13 at 18:38
0

To change the solution in the link to sort by descending order, just reverse the condition:

...
// Note: this comparator imposes orderings that are inconsistent with equals.    
public int compare(String a, String b) {
    if (base.get(a) >= base.get(b)) {
        return 1; // For ascending, return -1;
    } else {
        return -1; // For ascending, return 1;
    } // returning 0 would merge keys
}
...
Nicole
  • 32,841
  • 11
  • 75
  • 101