ozzymado
ozzymado

Reputation: 998

How to sort a Collection of generic Pairs

This is homework, so I would prefer some explanation rather than just giving me the answer.

I have a generic Pair class that can take any key value K, and any value V.

The goal is to write a generic method:

public static <...> Collection<Pair<...>> sortPairCollection(Collection <Pair<....>> col)

The only other guideline is that the K type must implement Comparable<...>.

After some digging, I saw people recommend something like this:

public static Collection<Pair<?,?>> sortPairCollection(Collection<Pair<?,?>> col)
{
    Collections.sort(col, new Comparator<Pair<?,?>>(){
        @Override
        public int compare(Pair<?, ?> x, Pair<?, ?> y) {
            return (Integer)x.v() - (Integer)y.v();
        }
    });
}

But that doesn't work for me, I get an error that says the sort method is not applicable to those parameters. I don't really know where to go from here.

Upvotes: 2

Views: 825

Answers (2)

Arun
Arun

Reputation: 1

Here is the complete program:

public static <K extends Comparable<? super K>, V extends Comparable<? super V>> void sortPairCollection(List<Pair<K, V>> col){

        Collections.sort(col, new Comparator<Pair<K,V>>(){

            public int compare(Pair<K, V> o1, Pair<K, V> o2) {

                int keyflag = o1.getValue().compareTo(o2.getValue()) == 0 ? o1.getKey().compareTo(o2.getKey()): o1.getValue().compareTo(o2.getValue()) ;

                return keyflag;

            }});

    }

Upvotes: -1

Paul Boddington
Paul Boddington

Reputation: 37665

Collections.sort only works on List instances, not on general Collections. It does not make sense to sort a HashSet for example.

Secondly, due to arithmetic overflow, you should avoid using subtraction in a comparator like that. It is always better to use Integer.compare.

Also, a method with return type Collection<Pair<?,?>> must return something. You could return col, but as you are mutating col it makes more sense to make the method void.

Another point is that it looks like your method will throw a ClassCastException unless the second type parameter is Integer (I am assuming v() has return type V). If this is the case, there is no point writing your method for Pair<?, ?> as you could just use Pair<?, Integer>.

Finally, due to the way generics work in Java, you won't actually be able to pass in a List<Pair<String, Integer>> with your current signature, because a List<Pair<String, Integer>> is not a List<Pair<?, Integer>> (see this question or this one). If you want to be able to do that, the argument should have type List<? extends Pair<?, Integer>>.

Edit

I now realise that I haven't really answered the question. The idea is not to mutate the original collection, but return a new one. Also the sorting should be done by key, not value, because K must implement Comparable.

In order to use the compareTo method, you need to indicate that K extends Comparable. The way to do this is to use the signature

public static <K extends Comparable<? super K>, V> Collection<Pair<K, V>> sortPairCollection(Collection<Pair<K, V>> col)

This is a bit of a mouthful - generics have significantly increased the complexity of method signatures.

K extends Comparable<? super K> says that Ks can be compared with other Ks.

You will still need to use a List though. You could use the ArrayList constructor that accepts a Collection.

As requested, I'll leave it up to you to write the correct code.

Upvotes: 6

Related Questions