Implementing compareTo() method in a Generic class - java

I have a project I'm working on and this is what I have started with:
public class Pair<T extends Comparable, E extends Comparable> implements Comparable{
private E e;
private T t;
public int compareTo(Pair arg0) {
// TODO Auto-generated method stub
return 0;
}
}
I need to use this class to sort ordered pairs in ascending order. If the first ones are equal, then it should sort by the send point.
Could you guys please help me get a start on this?

In your class definition, your T and E generics lack the comparison against themselves. This also happens for your Pair class. The definition of the class should be:
public class Pair<T extends Comparable<T>, E extends Comparable<E>> implements Comparable<Pair<T, E>> {
}
Now you can define how to compare the pair. Here's an example:
public class Pair<T extends Comparable<T>, E extends Comparable<E>> implements Comparable<Pair<T, E>> {
private E e;
private T t;
public int compareTo(Pair<T, E> pair) {
int result = t.compareTo(pair.t);
return (result == 0) ? e.compareTo(pair.e) : result;
}
}

Related

Need to add Comparable without modifying the class that is comparing

Code:
LinkedBinarySearchTree <Pair<String, Integer>> at = new LinkedBinarySearchTree<>();
Pair<String, Integer> p = new Pair<>(str, dni);
at.insert(p);
Pair is a class that has been given to me, it isn't the java class Pair (idk if java has a default pair class but just in case it has one, this one isn't that).
The class pair doesn't have a compareTo defined in it and the method insert uses the compareTo at some point and when it does it crashes.
I need to implement the abstract class Comparable and override the method compareTo in the class from the outside, without modifying the code of the class Pair, which means I have to do it from the "outside".
Is there a way to do this?
This is what I did previously:
public class MyComparator implements Comparator <Pair<String, Integer>> {
#Override
public int compare(Pair<String, Integer> o1, Pair<String, Integer> o2) {
final Collator instance = Collator.getInstance();
instance.setStrength(Collator.NO_DECOMPOSITION);
if (!o1.getFirst().equals(o2.getFirst())){
return o1.getFirst().compareTo(o2.getFirst());
} else {
return o1.getSecond().compareTo(o2.getSecond());
}
}
}
But it doesn't work with Comparator, it has to be Comparable for some reason and I don't know how to do it because I can't refer (this):
public class MyComparable implements Comparable <Pair<String, Integer>> {
#Override
public int compareTo(Pair<String, Integer> o) {
final Collator instance = Collator.getInstance();
instance.setStrength(Collator.NO_DECOMPOSITION);
//I can't use "this" here because ovbiously I'm not inside the class Pair so I don't know how to do it
if (!this.getFirst().equals(o.getFirst())){ //I can't use "this"
return this.getFirst().compareTo(o.getFirst());
} else {
return this.getSecond().compareTo(o.getSecond());
}
}
}
I need help please I've been trying to find an answer by myself and I'm out of ideas... I'm sorry if this question is too easy or unhelpful but I'm kinda struggling here :/.
EDIT:
I debugged the program and this is where it crashes, that's why I
think I need the Comparable:
public class DefaultComparator<E> implements Comparator<E> {
#Override
public int compare(E a, E b) throws ClassCastException {
return ((Comparable<E>) a).compareTo(b); //here
}
}
Could you possibly extend Pair with you own class that also implements Comparable and use that?
public class MyPair<T, O> extends Pair<T, O> implements Comparable<MyPair<T, O>> {
#Override
public int compareTo(MyPair<T, O> other) {
//logic to compare
}
}
and then use that
LinkedBinarySearchTree <MyPair<String, Integer>> at = new LinkedBinarySearchTree<>();
Edit based on comments:
If you know the types of objects used in the Pair are themselves Comparable then you can use bounded generic parameters. So the example above becomes:
public class MyPair<T extends Comparable<T>, O extends Comparable<O>> extends Pair<T, O> implements Comparable<MyPair<T, O>> {
#Override
public int compareTo(MyPair<T, O> other) {
//Now the compiler knows that T and O types are Comparable (that
//is they implement the Comparable interface) and
//this means their compareTo() can be used
return this.getFirst().compareTo(other.getFirst());
}
}
You can create a wrapper class to pair without changing pair but adding comparable to wrapper and after that you need to change your linkedlist's generic to ComparablePair
class ComparablePair implements Comparable < ComparablePair > {
private Pair < String,Integer > pair;
#Override
public int compareTo(ComparablePair o) {
Pair otherPair = o.pair;
//compare this.pair and otherpair here.
return 0;
}
}
LinkedBinarySearchTree <ComparablePair> at = new LinkedBinarySearchTree<>();

Java: sorting a generic class with two types

Suppose the following generic class with 2 types T, U
public class Pair<T, U> implements Comparable<T, U> { //Error 1
private final T first;
private final U second;
public Pair(T first_, U second_) {
first = first_;
second = second_;}
public T getFirst() { return first; }
public U getSecond() { return second; }
}
and the list of its items
List<Pair<Integer, Integer>> = new ArrayList<>()
that need to be sorted according to the first/second attribute. Unfortunately, the class definition contains some issue, the following error appears:
Error 1: wrong number of type arguments
How to design the comparator class? This code is probably completely wrong
public class SortBySecond implements Comparable <Pair <T, U>> {
public int compare(final Pair<T, U> p1, final Pair<T, U> p2) //Error 2
{
return t1.getSecond().compareTo(t2.getSecond()); //Updated comparator
}
}
Error 2 : Can not find symbols T, U, V
Thanks for your help.
Your Pair class should implement Comparable<Pair<T, U>> instead of Comparable<T, U>, which is a type that does not exist. You should also make sure that T and U are comparable.
There are lots of useful methods in the Comparator interface to help you compare things. You can use them to implement Comparable<Pair<T, U>>. In fact, you don't need to implement Comparable to sort the list. You only need to create a Comparator!
Here's how to implement Comparable:
class Pair<T extends Comparable<T>, U extends Comparable<U>> implements Comparable<Pair<T, U>> {
public int compare(final Pair<T, U> p1, final Pair<T, U> p2)
{
// this first compares the first field. If the first fields are the same, the second fields are compared
// If you have a different requirement, implement it accordingly.
return Comparator.comparing(Pair::getFirst).thenComparing(Pair::getSecond).compare(p1, p2);
}
}
To sort your list, do:
list.sort(Comparator.comparing(Pair::getFirst).thenComparing(Pair::getSecond));
To sort your list with only the second field, do:
list.sort(Comparator.comparing(Pair::getSecond));
You should make sure that your T and U types extend Comparable and make your Pair class implement Comparable<Pair<T,U>> :
public class Pair<T extends Comparable<T>, U extends Comparable<U>> implements Comparable<Pair<T,U>> {
private final T first;
private final U second;
public Pair(T first_, U second_) {
first = first_;
second = second_;}
public T getFirst() { return first; }
public U getSecond() { return second; }
#Override
public int compareTo(Pair<T, U> o) {
return this.second.compareTo(o.second);
}
}

How would I create an Object with these generics in Java? (<T extends KeyedItem<KT>, KT extends Comparable<? super KT>>)

Here are the Classes I'm using...
public class MyBinarySearchTreePlus<T extends KeyedItem<KT>, KT extends Comparable<? super KT>>
extends MyBinarySearchTree<T, KT> implements BSTPInterface<T, KT> {
public MyBinarySearchTreePlus() {
super();
}
}
.
public class MyBinarySearchTree<T extends KeyedItem<KT>, KT extends Comparable<? super KT>>
extends BinaryTreeBasis<T> {
public MyBinarySearchTree() {}
}
.
public abstract class BinaryTreeBasis<T> {
protected TreeNode<T> root;
public BinaryTreeBasis() {
root = null;
}
}
.
public abstract class KeyedItem<KT extends
Comparable<? super KT>> {
private KT searchKey;
public KeyedItem(KT key) {
searchKey = key;
}
}
Nothing I try will create a BinarySearchTree, I try:
MyBinarySearchTreePlus<Integer, Integer> tree = new MyBinarySearchTreePlus<Integer, Integer>();
I always get the error (coming from the first parameter):
Bound mismatch: The type Integer is not a valid substitute for the bounded
parameter <T extends KeyedItem<KT>> of the type MyBinarySearchTreePlus<T,KT>
What kind of Object is is T extends KeyedItem looking for? It doesn't compile with Comparable Objects, non-Comparable Objects, primitive Objects. So what exactly should I be using here? I don't understand why there's even 2 in the first place, obviously 1 is the type you are storing in the tree but whats's the other 1? I also have a TreeNode class of type T if that makes any difference.

how to upper-bound a self-referential type?

I have things (say, for context, numbers) that can perform operations on their own type:
interface Number<N> {
N add(N to);
}
class Int implements Number<Int> {
Int add(Int to) {...}
}
and actors that act on all subtypes of a certain upper bound:
interface Actor<U> {
<E extends U> E act(Iterable<? extends E> items);
}
I want to make an actor that acts polymorphically on any numerical type:
class Sum implements Actor<Number> {
<N extends Number<N>> N act(Iterable<? extends N> items) {...}
}
Now, clearly this doesn't work because Number and Number<N> are not the same. In fact, since Number doesn't constrain an implementor's type parameter to be its own type, such an actor could not possibly work. But I don't care to operate on Numbers in general - I am satisfied for my functionality to work only on Numbers of some type N extends Number<N>
As an alternative, I could declare:
interface Actor<E> {
E act(Iterable<? extends E> items);
}
class Sum<N extends Number<N>> implements Actor<N> {
N act(Iterable<? extends N> items) {...}
}
But this doesn't work for me because it forces me to know N when I construct my Sum, which my use case doesn't conveniently allow. It also forces an ugly <N extends Number<N>> on every class or method that polymorphically uses a Sum, causing a proliferation of type clutter.
Is there any elegant way to do what I want?
Example:
Here is some sample code expressing what I would like to do.
interface Folder<U> {
<E extends U> E fold(Iterable<? extends E> items);
}
class Sum implements Folder<Number> {
<N extends Number<N>> N fold(Iterable<? extends N> items) {
Iterator<? extends N> iter = items.iterator();
N item = iter.next();
while (iter.hasNext())
item = item.add(iter.next());
return item;
}
}
class Concat implements Folder<String> {
<S extends String> fold(Iterable<? extends S> items) {
StringBuilder concatenation = new StringBuilder();
for (S item : items)
concatenation.append(item);
return concatenation.toString();
}
}
class FoldUtils {
static <U, E extends U> E foldDeep(Folder<U> folder, Iterable<? extends Iterable<? extends E>> itemses) {
Collection<E> partialResults = new ArrayList<E>();
for (Iterable<? extends E> items : itemses)
partialResults.add(folder.fold(items));
return folder.fold(partialResults);
}
}
Looking at your example, I'm not sure what you gain from having the generic method provide the concrete parameter vs having it in the actor:
class Sum<T extends Number<T>> implements Actor<T> {
T act(Iterable<? extends T> items) {...}
}
What's the virtue of having a Sum<any-self-referential-Number> vs just having a Sum<Int>, and a Sum<Float>, etc?
If you're worried about the tiny memory overhead of creating different instances, you could just return the same instance each time with an unchecked cast, as is common where safe (see e.g. Guava's Optional.absent() or Collections.emptyList()).
In your example, somebody's eventually going to have to essentially do:
List<List<Int>> list;
foldDeep(new Sum(), list)
So why not just require the type parameter there?
foldDeep(new Sum<Int>(), list)
Or if encapsulated behind a factory,
foldDeep(Sum.instance(), list)
foldDeep(NumberFolders.sum(), list)
In short, it's not clear to me why this wouldn't work just as well:
interface Folder<U> {
U fold(Iterable<? extends U> items);
}
class Sum<T extends Number<T>> implements Folder<T> {
public T fold(Iterable<? extends T> items) {
//...
}
}
class FoldUtils {
static <E> E foldDeep(Folder<E> folder, Iterable<? extends Iterable<? extends E>> itemses) {
Collection<E> partialResults = new ArrayList<>();
for (Iterable<? extends E> items : itemses)
partialResults.add(folder.fold(items));
return folder.fold(partialResults);
}
}
//...
FoldUtils.foldDeep(new Sum<>(), list);

Is this forbidden in Java Generics?

class Collator<S extends Stream<E extends Comparable<E>>> {
S s;
E e;
public <S> Collator(List<S> streams){
s = streams.get(0);
e = s.read();
}
public <E> E next(){
return e;
}
}
interface Stream<E extends Comparable<E>>{
public E read();
}
class Record implements Comparable<Record>{
public Integer time;
public int compareTo(Record r){
return this.time.compareTo(r.time);
}
}
Especially 1st line:
class Collator<S extends Stream<E extends Comparable<E>>>
I expect to say:
Define a collator that works on Streams of Entries where each Entry implements comparable.
you miss-qualified the generic parameters
class Collator<S extends Stream<E>,E extends Comparable<E>> {
S s;
E e;
public Collator(List<S> streams){
s = streams.get(0);
e = s.read();
}
public E next(){
return e;
}
}
interface Stream<E extends Comparable<E>>{
public E read();
}
class Record implements Comparable<Record>{
public Integer time;
public int compareTo(Record r){
return this.time.compareTo(r.time);
}
}
this compiles
in particular the line class Collator<S extends Stream<E>,E extends Comparable<E>> it means a Collator that works on a S that is a Stream of E and E implement Comparable
Some glass ball guessing, since you don't show your error message:
Your constructor and method are declaring new type parameters <E> and <S> which are shadowing the type parameters of your class. Remove them.
Then, E should be a type parameter of your class, too.
class Collator<E extends Comparable<E>, S extends Stream<E>> {
S s;
E e;
public Collator(List<S> streams){
s = streams.get(0);
e = s.read();
}
public E next(){
return e;
}
}
interface Stream<E extends Comparable<E>>{
public E read();
}
class Record implements Comparable<Record>{
public Integer time;
public int compareTo(Record r){
return this.time.compareTo(r.time);
}
}
The problem is E extends Comparable
Define a collator that works on Streams of Entries where each Entry implements comparable of a given type:
public class Collator<T,E extends Comparable<T>, S extends Stream<E>>

Categories