3

I'm trying to sort a java.util.Map as follows.

public final class SortMapByValue <K, V extends Comparable<? super V>> implements Comparator<Map.Entry<K, V>>
{
    @Override
    public int compare(Entry<K, V> o1, Entry<K, V> o2) {
        return (o1.getValue()).compareTo(o2.getValue());
    }

    public static <K, V extends Comparable<? super V>> Map<K, V> sortMapByValue(Map<K, V> unsortedMap)
    {
        List<Map.Entry<K, V>> list = new LinkedList<Map.Entry<K, V>>(unsortedMap.entrySet());            
        Collections.sort(list);  //Compiler error here.
        Map<K, V> sortedMap = new LinkedHashMap<K, V>();

        for (Map.Entry<K, V> entry : list) {
            sortedMap.put(entry.getKey(), entry.getValue());
        }
        return sortedMap;
    }
}

As commented in the code, it issues a compile-time error as follows.

no suitable method found for sort(List<Entry<K,V>>)
    method Collections.<T#1>sort(List<T#1>,Comparator<? super T#1>) is not applicable
      (cannot instantiate from arguments because actual and formal argument lists differ in length)
    method Collections.<T#2>sort(List<T#2>) is not applicable
      (inferred type does not conform to declared bound(s)
        inferred: Entry<K,V>
        bound(s): Comparable<? super Entry<K,V>>)
  where K,V,T#1,T#2 are type-variables:
    K extends Object declared in method <K,V>sortMapByValue(Map<K,V>)
    V extends Comparable<? super V> declared in method <K,V>sortMapByValue(Map<K,V>)
    T#1 extends Object declared in method <T#1>sort(List<T#1>,Comparator<? super T#1>)
    T#2 extends Comparable<? super T#2> declared in method <T#2>sort(List<T#2>)

This could also be done in the following way in the sortMapByValue() method as follows.

Collections.sort(list, new Comparator<Map.Entry<K, V>>()
{
    @Override
    public int compare(Map.Entry<K, V> o1, Map.Entry<K, V> o2) {
        return (o1.getValue()).compareTo(o2.getValue());
    }
});

But instead, I would like fixing the the error to follow that way (avoiding this anonymous comparator). How to fix that error?

Tiny
  • 27,221
  • 105
  • 339
  • 599
  • 3
    You have a `List` of `Entry`'s. The class `Entry` does not implement `Comparable`. However, `Collections.sort(..)` expects a `List` of some type that implements `Comparable`. – Sotirios Delimanolis Mar 02 '14 at 19:17
  • So you have code that doesn't compile, and code that works perfectly. The problem with the code that works is that you want to use the code that doesn't compile, and the problem with the code that doesn't compile is that you want it to compile. Do I have that right? – ruakh Mar 02 '14 at 19:19
  • You need to pass the comparator to Collections.sort, for example like Collections.sort(list, new SortMapByValue()); – Gábor Bakos Mar 02 '14 at 19:19
  • possible duplicate of [How to sort a Map on the values in Java?](http://stackoverflow.com/questions/109383/how-to-sort-a-mapkey-value-on-the-values-in-java) – Svetlin Zarev Mar 02 '14 at 19:50
  • Liable to be closed as *unclear what you're asking*, really? :) – Tiny Mar 10 '14 at 05:32

1 Answers1

8

Map.Entry does not implement Comparable, so Collections.sort(List<Entry>) has no way to know how the entries should be sorted. So you have to provide a Comparator.

But since your SortMapByValue already implements the Comparator interface, you can simply use an instance of that class:

Collections.sort(list, new SortMapByValue<>());

Also note that with Java 8 you can significantly reduce the length of the code:

public static <K, V extends Comparable<? super V>> Map<K, V> sortMapByValue(Map<K, V> unsortedMap) {
    return unsortedMap.entrySet().stream()
            .sorted(comparing(Entry::getValue))
            .collect(toMap(Entry::getKey, Entry::getValue, (e1,e2) -> e1, LinkedHashMap::new));
}
assylias
  • 321,522
  • 82
  • 660
  • 783