问题
For one of the Homeworks in my class, we have a collection of a class titled Pair and we need to sort it in ascending order based on the value of the key.
I could apply this if the keys were strings or integers, but how do I write code that would compare my items when they're Generic as seen below?
The professor in my class explained what to do for integers or strings but when my variables are generic I'm at a complete loss.
Below are copies of the relevant parts of my code.
import java.util.*;
public class Utils {
public static<K extends Comparable<K>, V> Collection<Pair<K,V>> sortPairCollection(Collection <Pair<K,V>> col){
ArrayList <Pair<K,V>> list = new ArrayList<>();
//Code to compare
return list;
}
public static void main(String[] args) {
ArrayList <Pair<String,Integer>> list = new ArrayList<>();
Pair<String, Integer> e = new Pair<>("One", 1);
list.add(e);
Pair<String, Integer> f = new Pair<>("Two", 2);
list.add(f);
Utils help = new Utils();
help.sortPairCollection(list);
}
}
This second part here is the code for my Pair class. import java.io.Serializable; import java.util.Objects;
public class Pair <K,V> extends Object implements Serializable, Cloneable{
public Pair(K k, V v){
this.k = k;
this.v = v;
}
public K k(){
return k;
}
public V v(){
return v;
}
/*
... //irrelevant data omitted
*/
private final K k;
private final V v;
}
回答1:
Option 1.Use a Comparator
public class Cmp<K extends Comparable<K>, V> implements Comparator<Pair<K, V>> {
@Override
public int compare(Pair<K, V> o1, Pair<K, V> o2) {
return o1.k.compareTo(o2.k);
}
}
public class Utils {
public static <K extends Comparable<K>, V> Collection<Pair<K, V>> sortPairCollection(
Collection<Pair<K, V>> col) {
ArrayList<Pair<K, V>> list = new ArrayList<>();
Collections.sort(list, new Cmp<>());
return list;
}
}
Option 2. Implement Comparable
public class Pair<K extends Comparable<K>, V> implements Comparable<Pair<K, V>> {
private K k;
private V v;
@Override
public int compareTo(Pair<K, V> o) {
return k.compareTo(o.k);
}
}
public class Utils {
public static <K extends Comparable<K>, V> Collection<Pair<K, V>> sortPairCollection(Collection<Pair<K, V>> col) {
ArrayList<Pair<K, V>> list = new ArrayList<>();
Collections.sort(list);
return list;
}
}
Or just
public class Utils {
public static <K extends Comparable<K>, V> Collection<Pair<K, V>> sortPairCollection(Collection<Pair<K, V>> col) {
ArrayList<Pair<K, V>> list = new ArrayList<>();
Collections.sort(list, (p, o) -> p.k.compareTo(o.k));
return list;
}
}
You don't have do create an instance for your static method btw. just invoke
Utils.sortPairCollection(list);
回答2:
import java.util.*;
public class Utils {
public static <K extends Comparable<K>, V> Collection<Pair<K, V>> sortPairCollection(Collection<Pair<K, V>> col) {
ArrayList<Pair<K, V>> list = new ArrayList<>(col);
//Code to compare
list.sort(Comparator.comparing(Pair::k)); //this is the only change needed
return list;
}
public static void main(String[] args) {
List<Pair<String, Integer>> listas = Arrays.asList(
new Pair<>("One", 1),
new Pair<>("Two", 2));
System.out.println(Utils.sortPairCollection(listas));
}
What we did here is that we extracted an already Camparable
key from our Pair
and passed that to the Comparator
class static method which will generate a custom Comparator
for our Pair
class.
See the Javadoc for Comaparator
here
回答3:
If you are a clean and elegant code lover like me then you can use the power of lambda expression to create an anonymous function (function with no name) on the spot that handles the comparison logic. Technically it is the same as when using Comparable
or Comparator
functional interfaces but using lambdas you don't have to write boilerplate code by creating classes just for one function. Instead you create that function on spot int the form of lambda expression, java handles the rest. Lambda expressions were introduced in Java 8.
Lambda expression have the form ( <parameters> ) -> { //body of the function }
public class Pair<K ,V extends Comparable<V>> {
private K k;
private V v;
public Pair(K k, V v){
this.k = k;
this.v = v;
}
public K k(){
return k;
}
public V v(){
return v;
}
}
public static void main(String[] args) {
ArrayList <Pair<String,Integer>> list = new ArrayList<>();
Pair<String, Integer> e = new Pair<>("One", 1);
list.add(e);
Pair<String, Integer> f = new Pair<>("Two", 2);
list.add(f);
// Second argument to this sort function is a lambda expression
Collections.sort( list , (pair1 , pair2)->{
return pair1.v().compareTo(pair2.v());
});
}
}
The data type of pair1
and pair2
will be Pair
Here are some starter links about lambda expression and functional interfaces
Functional Interfaces: https://www.geeksforgeeks.org/functional-interfaces-java/
Lambda Expressions: https://www.geeksforgeeks.org/lambda-expressions-java-8/
来源:https://stackoverflow.com/questions/53202231/using-comparable-to-compare-generic-variables