Tommy Chheng

Icon

All Things Programming!

Sorting a HashMap by Value in Java vs Ruby

I’m working a graph problem in Java where I need to sort nodes by its edge count. I have a HashMap of nodes to edge count so I just need to sort a HashMap by its value.
A quick Google search brought up a few solutions. Below is a snippet of a typical solution from StackOverFlow


public static > List getKeysSortedByValue(Map map) {
    final int size = map.size();
    final List> list = new ArrayList>(size);
    list.addAll(map.entrySet());
    final ValueComparator cmp = new ValueComparator();
    Collections.sort(list, cmp);
    final List keys = new ArrayList(size);
    for (int i = 0; i < size; i++) {
        keys.set(i, list.get(i).getKey());
    }
    return keys;
}
private static final class ValueComparator>
                                     implements Comparator> {
    public int compare(Map.Entry o1, Map.Entry o2) {
        return o1.getValue().compareTo(o2.getValue());
    }
}

Can you believe it?? >10 lines of verbose madness! The Ruby solution is:

>> x = {:a => 1, :b => 2, :c => 1, :d => 5}
>> x.keys.sort_by{|k| x[k]}
=> [:a, :c, :b, :d]

This makes you really appreciate closure support in languages. Java 7′s support of closure should bring more sanity to the Java world.

I’m also learning Clojure right now, the solution is just as nice as Ruby.

user=> (def x {:a 1 :b 2 :c 1 :d 5})
user=> (sort-by #(x %) (keys x))
(:a :c :b :d)

edit:
In Scala, it is also very succinct:


scala> val x = Map('a' -> 1, 'b' -> 2, 'c' -> 1, 'd' -> 5)
x: scala.collection.immutable.Map[Char,Int] = Map((a,1), (b,2), (c,1), (d,5))
scala> x.keysIterator.toList.sortWith((key1,key2) => x(key1) < x(key2))
res5: List[Char] = List(a, c, b, d)

Category: Ruby

Tagged: , , ,

  • Groovy is the coolest (i.e., most productive for Java programmers) way to do closures on the JVM. But your example doesn't even need a closure:

    [a:1, b:2, c:1, d:5].keySet().sort()
    ==>
    [a, b, c, d]

    But say you wanted something other than the default order:

    [a:1, b:2, c:1, d:5].keySet().sort { - (it[0] as int) }
    ==>
    [d, c, b, a]

    The dandy thing is those are real Java Collections (Collection, List, Set, Map), so that works with a gigantic base of existing Java libraries.
  • #(x %) is here equivalent to x, so it's better to write (sort-by x (keys x))
blog comments powered by Disqus