Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic method to Sort a Map on Values

Tags:

java

generics

I have a small program that is supposed to sort a map based on its values. Here is what I have so far:

    public static <K, V extends Comparable< ? extends V>> Map<K, V> 
    sortByValues(final Map <K, V> mapToSort)
    {
        List<Map.Entry<K, V>> entries = 
            new ArrayList<Map.Entry<K, V>>(mapToSort.size());

        entries.addAll(mapToSort.entrySet());

        Collections.sort(entries, new Comparator<Map.Entry<K, V>>()
        {
            public int compare(
                               final Map.Entry<K, V> entry1, 
                               final Map.Entry<K, V> entry2)
            {
                return entry1.getValue().compareTo(entry2.getValue());
            }
        });

        Map<K, V> sortedMap = new LinkedHashMap<K, V>();

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

        return sortedMap; 
    }

I want my generic value V to be comparable to anything that is either V or is a at least a subclass of V.

I get the following error for the code piece :

public static <K, V extends Comparable< ? extends V>>

Bound mismatch: The method compareTo(? extends V) of type V is not applicable for the arguments (V). The wildcard parameter ? extends V has no lower bound, and may actually be more restrictive than argument V

How can it be more restrictive?

If I change the declaration to:

public static <K, V extends Comparable< ? super V>>

then there is no error. But this is not what I want.

One workaround I have is that, I can change the declaration to:

public static <K, V extends Comparable<V>>

but doing this I lose the flexibility in that I cannot pass a Map whose value implements Comparable with a subclass of itself.

Apologies for such a long question. Thanks in advance.

like image 527
Swaranga Sarma Avatar asked Jun 09 '11 09:06

Swaranga Sarma


People also ask

How can we sort map by values?

Sorting HashMap by Value Simple Example To sort the String values in the list we use a comparator. This comparator sorts the list of values alphabetically. Once, we have sorted the list, we build the HashMap based on this sorted list. HashMap entries are sorted according to String value.

Can I sort a map in Java?

In Java, sorting HashMap by values is complicated because there is no direct method is available. To sort the HashMap by values, we need to create a Comparator. It compares two elements based on the values. After that get the Set of elements from the Map and convert Set into the List.

What is generic sorting?

We can define a sorting method itself to be generic, so that it takes a type argument as a parameter and sorts arrays of objects of that type. • Instead of having different programs to sort different types of objects, we would have one program that handles multiple types.


2 Answers

I think your second option, namely

public static <K, V extends Comparable<? super V>>

is the way to. I think this is so because when you write

public static <K, V extends Comparable<C extends V>>

you basically say that you want to be able to compare any instance of V to any instance of C. But what is missing here is, that because you want to call Collections.sort(..) internally, you also must be able to compare any instance of C to any instance of V. But the generics do not express this, and rightfully the compiler complains.

Basically, to sort some values (at least using Collections.sort(..)) they must be mutually comparable, but the generic restrictions you envision only guarantee that you can compare in one direction.

like image 178
Waldheinz Avatar answered Oct 31 '22 15:10

Waldheinz


implements Comparable with a subclass of itself.

This is "poor design": As a good general rule, classes should not know about their subclasses.

What use case do you have in mind?

I think public static <K, V extends Comparable<V>> is fine.

like image 20
Bohemian Avatar answered Oct 31 '22 15:10

Bohemian