Need to add Comparable without modifying the class that is comparing - java

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<>();

Related

Are java comparators Type-aware?

I wanted a simple way to create a Comparator object based on any given Comparable class, so I coded the ComparatorCreator object, which I believed would look at the type of its generic and return the proper Comparator object that I could use to compare objects of that type. So I wrote the following code to test my idea. my belief would be that since the BackwardsInt class' compareto method is a reversed Comparator, it should be able to compare any two numbers in reverse order. But as it went through the statements, it completely ignored the reversal when it was comparing two ints, and even threw an error. I want to know why this is happening. The comparator I created seems to be aware of the type of the Number I'm passing in its arguments.
(I also got really into bounded wildcards a while back, so if that caused the problem, then oops).
import java.util.Comparator;
public class what {
public static void main(String[] ignoreme)
{
Comparator comp = new ComparatorCreator<BackwardsInt>().getComparator();
//comp should represent a Comparator<Number> which redirects to BackwardsInt.compareTo
int big=6;
int small=2;
BackwardsInt bbig=new BackwardsInt(6);
BackwardsInt bsmall=new BackwardsInt(2);
System.out.println(comp.compare(bbig, bsmall));//prints -1 good
System.out.println(comp.compare(bbig, small));//prints -1 good
System.out.println(comp.compare(big, small));//prints 1 why?
System.out.println(comp.compare(big, bsmall));//throws error?!?
}
private static class ComparatorCreator<T extends Comparable<? super T>>{
public Comparator<? extends T> getComparator()
{
return T::compareTo;
}
}
private static class BackwardsInt extends Number implements Comparable<Number>{
private int val;
public BackwardsInt(int v)
{
val=v;
}
#Override
public int compareTo(Number o) {
double d = o.doubleValue()-val;
if(d>0)
return 1;
if(d<0)
return -1;
return 0;
}
public int intValue() {
return val;
}
public long longValue() {
return val;
}
public float floatValue() {
return val;
}
public double doubleValue() {
return val;
}
}
}
Lets look at your ComponentCreator
private static class ComparatorCreator<T extends Comparable<? super T>>{
public Comparator<? extends T> getComparator()
{
return T::compareTo;
}
}
If have slightly changed it to make your mistake more clear
private static class ComparatorCreator<T extends Comparable<? super T>>{
public Comparator<? extends T> getComparator()
{
return (o1, o2) -> {
return o1.compareTo(o2);
};
}
}
The method reference you used is the same as the lambda I have but it makes the mistake more obvious. If we check your samples one by one we can see the following:
comp.compare(bbig, bsmall); // calls bbig.compareTo(bsmall)
comp.compare(bbig, small); // calls bbig.compareTo(small)
comp.compare(big, small); // calls big.compareTo(small)
comp.compare(big, bsmall); // calls big.compareTo(bsmal)
The output you received makes sense because big.compareTo() will call the compareTo() function of the Integer class.

ConcurrentSkipListMap add Comparator defined in generic class

I have this class:
public abstract class Orderable<ID, T extends Comparable, V extends Orderable> implements Comparator<V>{
public abstract ID getId();
public abstract T getOrderParam();
public int compare(V o1, V o2) {
int compared = o1.getRankParam().compareTo(o2.getRankParam());
if (compared == 0) return o2.getId().toString().compareTo(o1.getId().toString());
return compared;
}
Now I'd like to create a ConcurrentSkipListMap passing as Comparator what I defined in Orderable Class. The goal is to keep ConcurrentSkipListMap ordered with comparator of V, where V is a generic class that extend Orderable.
private volatile ConcurrentSkipListMap<ID, V> concurrentSkipListMap;
private volatile AtomicInteger size;
public LeaderBoardImpl() {
concurrentSkipListMap = new ConcurrentSkipListMap<ID, V>(**** HERE I NEED TO PASS COMPARATOR****);
size = new AtomicInteger(0);
}
I'm not sure how to pass a Comparator of a generic Class.
Thanks
Albert

Declaring generics

I have a problem with defining generics in static methods and fields.
Suppose I have a simple interface, used by all classes that contains a field of type T called value:
public interface HasValue<T> {
// Getter:
public T value();
// Setter:
public void setValue(T value);
}
If I have an array of object of a type N that implements HasValue<T>, I may have necessity to order this array. One classical way is to compare those N objects using their value field: if T implements the Comparable<T> interface and both arg0 and arg1 are of type N, then arg0.compareTo(arg1) will be equal to arg0.value().compareTo(arg1.value()).
The goal is to create a usable, not time-consuming, possible simple way to obtain the aforementioned situation.
A possibility would be to create a custom Comparator<N> every time I need something similar. That would force me to write code each time: definitly time consuming.
I could create that Comparator<N> directly in the interface. The first try is to create a method:
It needs to be a default method. Part of the code will test if the class T implements the Comparable interface or not, and for that I need an example of the T class: using this.value().getClass() is the fastest way. With a static method I could not use this.
I need to explicitate that the N class implements the interface HasValue<T>, otherwise the computer will not know.
public default <N extends HasValue<T>> Comparator<N> COMPARE_BY_VALUE() throws Exception{
if(Comparable.class.isAssignableFrom(this.value().getClass()))
return new Comparator<N>() {
public int compare(N arg0, N arg1) {
Comparable value0 = (Comparable) arg0.value(),
value1 = (Comparable) arg1.value();
return value0.compareTo(value1);
}
};
else throw new Exception("The class of the value does not implement the interface Comparable.\n");
}
This strategy works... barely. It's clumsy, involves rawtypes, creates the Comparator<N> every time.
Second try: creating a static field.
The strategy is to separate the testing problem from the rest. A default method will do the test: in case of success the method will return a static Comparator, otherwise an exception.
public default <N extends HasValue<T>> Comparator<?> COMPARE_BY_VALUE() throws Exception{
if(Comparable.class.isAssignableFrom(this.value().getClass()))
return COMPARE_BY_VALUE;
else throw new Exception("The class of the value does not implement the interface Comparable.\n");
}
public static Comparator<HasValue> COMPARE_BY_VALUE = new Comparator() {
public int compare(Object arg0, Object arg1) {
Comparable value0 = (Comparable) ((HasValue)arg0).value(),
value1 = (Comparable) ((HasValue)arg1).value();
return value0.compareTo(value1);
}
};
While declaring the static field I (unfortunately) cannot state something like public static <T, N extends HasValue<T>> Comparator<N> COMPARE_BY_VALUE. That forces me to return a Comparator<HasValue>: not what I wanted.
Using wildcards I can obtain something close:
public default <N extends HasValue<T>> Comparator<?> COMPARE_BY_VALUE() throws Exception{
if(Confrontable.class.isAssignableFrom(this.value().getClass()))
return COMPARE_BY_VALUE;
else throw new Exception("The class of the value does not implement the interface Comparable.\n");
}
public static Comparator<? extends HasValue<? extends Comparable<?>>> COMPARE_BY_VALUE
= new Comparator() {
public int compare(Object arg0, Object arg1) {
Comparable value0 = (Confrontable) ((HasValue<?>)arg0).value(), value1 = (Confrontable) ((HasValue<?>)arg1).value();
return value0.compareTo(value1);
}
};
This modification will return (in theory) a Comparator<N> where N extends HasValue<T>, T extends Comparable<U> and U is actually T.
That because every ? in Comparator<? extends HasValue<? extends Comparable<?>>> is interpreted by the JVM as a potential new class: three ? means three new class (N, T and U), and it happens that T implements Comparable<T> - thus U and T are one and the same.
I still have a great amount of rawtypes...
...but at least I have only one Comparator for each N and T.
Now, while the last strategy seems to works, I would like to know if there is a better way to obtain my goal.
My initial idea was to state something like
public static <T extends Comparable<T>, N extends HasValue<T>> Comparator<N> COMPARE_BY_VALUE = new Comparator() {
public int compare(N arg0, N arg1) {
return arg0.value().compareTo(arg1.value());
}
};
and obtain a Comparator<N> without wildcars. This however sends all types of errors. Someone has an idea?
Just do:
static <T extends Comparable<T>> Comparator<HasValue<T>> createValueComparator() {
return new Comparator<HasValue<T>>() {
#Override
public int compare(HasValue<T> o1, HasValue<T> o2) {
return o1.value().compareTo(o2.value());
}
};
}
This reads: for every type T which implements Comparable this method returns comparator which can compare HasValue<T>.
Java might not be able to properly infer types in such convoluted constructs. You might have to add the types explicitly:
Collections.sort(list, Main.<Integer> createValueComparator());
or:
Comparator<HasValue<Integer>> comparator = createValueComparator();
Collections.sort(list, comparator);
Keep in mind that a lot of programmers overuse generics. Usually there is a simpler way to achieve the same - while still maintaining type safety.

Why doesn't type inference work in this case

I want to write a comparator which sorts objects having a parameter of type Number. I created a generic dto as follows
public class GenericSortingDTO<T extends Number> {
private T parameter;
public T getParameter() {
return parameter;
}
public void setParameter(T parameter) {
this.parameter = parameter;
}
}
I created a comparator like this
import java.math.BigDecimal;
import java.util.Comparator;
public class WeightComparator implements Comparator<GenericSortingDTO<Number>> {
#Override
public int compare(GenericSortingDTO<Number> o1,
GenericSortingDTO<Number> o2) {
return new BigDecimal(o1.getParameter().toString()).compareTo(new BigDecimal(o2.getParameter().toString()));
}
}
Now, I try to create an instance of an integer comparator
Comparator<GenericSortingDTO<Integer>> genericComparator = new WeightComparator();
But I get an error: Type mismatch: cannot convert from WeightComparator to Comparator<GenericSortingDTO<Integer>>
But it doesn't give a compilation error when I do this:
Comparator<GenericSortingDTO<Number>> genericComparator = new WeightComparator();
Can somebody explain this behaviour?
GenericSortingDTO<Integer>
and
GenericSortingDTO<Number>
are two disparate types. There is no hiererachical relationship between them. By implication the same is true of
Comparator<GenericSortingDTO<Integer>>
and
Comparator<GenericSortingDTO<Number>>
These two types are not assignment-compatible, therefore the compiler error.
However, there is no need to restrict your WeightComparator as you have. You are allowed to declare
public class WeightComparator implements Comparator<GenericSortingDTO<? extends Number>> {
#Override public int compare(GenericSortingDTO<? extends Number> o1, GenericSortingDTO<? extends Number> o2) {
return ...;
}
}
And since Numbers are comparable on their own, you'll be able to provide a meaningful implementation.
It would be simpler to declare your class like this:
public static class GenericSortingDTO<T extends Number>
implements Comparator<GenericSortingDTO<T>> {
//your current code here
#Override
public int compare(GenericSortingDTO<T> o1, GenericSortingDTO<T> o2) {
return new BigDecimal(o1.getParameter().toString()).compareTo(new BigDecimal(o2.getParameter().toString()));
}
}

Implementing compareTo() method in a Generic class

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;
}
}

Categories