comparing two generic objects if the one is "greater" or "smaller" - java

I want to generate a binary tree with key - value pairs in their nodes.
In my binary tree I want to implement nodes at the beginning with an insert method, which implements a new left node if the key is smaller than the key of the current node. Then if there is already a left node it will check again for it. The same logic follows for right/greater node inserts.
I wrote my code first using the int type because it's way easier for me to test my code before I use generics (new topic for me). It worked when using int but I an unsure how to compare two generics with themselves by using "<" or ">".
public ListCell<Type> checkKey(Type key, ListCell<Type> checkCell) {
ListCell<Type> newCell = null;
if (key < checkCell.key && checkCell.left != null) {
...
}
...
}
I don't know if it's worth saying but I'm creating my binary tree with a selfcoded list.
Above you can see my current checks but i can't compare my given key now with checkCell.key because of them not being numbers.
So my general question is how to compare the keys in generics if they are "smaller" or "greater" than the other for my implementation in a binary tree.
Thanks in advance

You would need to ensure that your generic type implemented the Comparable interface, and then use the compareTo method instead. Java does not support overloading the > operator (or any operator overloading, for that matter).
As per the documents, compareTo:
Returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.
An example (that you'll have to map on to your exact code), assuming that key is your item you will store in your node, and checkCell.key is your node
int compareResult = key.compareTo(checkCell.key);
if (key < 0) { // it goes on the left }
else if (key == 0) { // it is the same }
else { // it goes on the right }
In your compareTo method you need to decide what fields in your class determine it's "ordering". For example, if you have a size and priority field, you might do:
#Override public int compareTo(Type other) {
final int BEFORE = -1;
final int EQUAL = 0;
final int AFTER = 1;
if (this == other) return EQUAL;
if (this.size < other.size) return BEFORE;
else if (this.size > other.size) return AFTER;
else { // size is equal, so test priority
if (this.priority < other.priority) return BEFORE;
else if (this.priority > other.priority) return AFTER;
}
return EQUAL;
}

Bounded type parameters are key to the implementation of generic algorithms. Consider the following method that counts the number of elements in an array T[] that are greater than a specified element elem.
public static <T> int countGreaterThan(T[] anArray, T elem) {
int count = 0;
for (T e : anArray)
if (e > elem) // compiler error
++count;
return count;
}
The implementation of the method is straightforward, but it does not compile because the greater than operator (>) applies only to primitive types such as short, int, double, long, float, byte, and char. You cannot use the > operator to compare objects. To fix the problem, use a type parameter bounded by the Comparable<T> interface:
public interface Comparable<T> {
public int compareTo(T o);
}
The resulting code will be:
public static <T extends Comparable<T>> int countGreaterThan(T[] anArray, T elem) {
int count = 0;
for (T e : anArray)
if (e.compareTo(elem) > 0)
++count;
return count;
}
bounded type parameters

Related

Java generics method fails on number comparison

See the tiny method below. The boo1 = ... line goes fine, probably as it does object ID comparison. The second boo2 = ... line gives a compile error "Operator > cannot be applied to T,T". I don't understand why. After all T extends Number (as you can see in the method signature), so comparisons like > should be possible. What am I doing wrong?
public static <T extends Number> int[] where(T[] arr, T val) {
if (arr == null || arr.length == 0) return null;
boolean boo1 = arr[0] == val; //Compiles happily, as does "!="
boolean boo2 = arr[0] > val; //Doesn't compile (nor does ">=", "<", "<="
return null;
}
What am I doing wrong?
You're assuming that the relational operators support Number operands; they don't. Only Numbers that box primitive types (e.g. Integer, Long) do; others such as BigInteger don't.
You can add an additional bound to T to require it to be Comparable:
<T extends Number & Comparable<T>>
And you can pass in any types that are both Numbers and are Comparable: this includes Integer, Long, BigInteger etc.
Then you can use:
arr[0].compareTo(val) > 0
(but you might care to watch out for nulls).
Also, you shouldn't be using == and != to check for equality/inequality: use equals instead:
arr[0].equals(val) // Instead of ==
!arr[0].equals(val) // Instead of !=
You can, alternatively, use arr[0].compareTo(val) ==/!= 0. That may be better, in fact, because e.g. BigInteger and BigDecimal have equals methods that consider scale, so [1.00].equals([1.0]) is false, whereas [1.00].compareTo([1.0]) == 0 is true. Ultimately, it depends on what you're trying to achieve as to which way to choose.
Try it this way:
public static <T extends Number> int[] where(T[] arr, T val) {
if (arr == null || arr.length == 0) return null;
boolean boo1 = arr[0] == val; //Compiles happily, as does "!="
boolean boo2 = arr[0].intValue() > val.intValue();
// Or doubleValue()
return null;
}

How to define a generic comparable array class?

I want to define a generic class ComparableList<> that extend ArrayList and implements Comparable interfaces, such that two objects of type ComparableList can be compared using the compareTo method. The compareTo should perform a lexicographic comparison.
Here's my code:
class ComparableList <T extends Comparable<T>> extends ArrayList implements Comparable<ComparableList>{
#Override
public int compareTo(ComparableList o){
Iterator citer = this.iterator();
Iterator oiter = o.iterator();
while (citer.hasNext() && oiter.hasNext()){
if (citer.next() > oiter.next()){
return 1;
}else if (citer.next() < oiter.next()){
return -1;
}else {
if (!citer.hasNext()){
return -1;
}
if(!oiter.hasNext()){
return 1;
}
}
}
return 0;
}
}
and I got error messages like this:
TCL.java:11: error: bad operand types for binary operator '>'
if (citer.next() > oiter.next()){
^
first type: Object
second type: Object
TCL.java:13: error: bad operand types for binary operator '<'
}else if (citer.next() < oiter.next()){
^
first type: Object
second type: Object
I thought it should be a ComparableList but not an Object. Can anyone tell me the reason?
You need to compare the objects using Comparable.comapreTo() (that's why you have <T extends Comparable<T> there). You need to first check for nulls on either side.
Also, each call to Iterator.next() iterates to next element, you don't want to call it twice in one loop iteration - store the items at the loop start then use the stored values.
Comparable doesn't override the > and < operators (nothing can). Since your T implements Comparable, use compareTo:
int result = citer.next().compareTo(oiter.next());
if (result != 0) {
return result;
} else {
if (citer.hasNext()) {
return -1;
}
if (oiter.hasNext()) {
return 1;
}
}
Note that that also calls next only once per iteration, since next advanced the iterator.
Each element in your ComparableList is of type T extends Comparable<T>, for sure the binary operator is not available for it (Java doesn't have operator overloading), but since it extends Comparable, you have compareTo to be used as replacement for < and >. Use it instead.

CompareTo method not working

I am implementing a Binary Search Tree using BinaryNode to store the data. I am using a CompareTo method in my add and contains methods to determine which sub tree the item belongs in. I keep getting this error various places where compare is used:
BST.java:50: error: cannot find symbol
if (item.CompareTo(root.data) > 0)
^
symbol: method CompareTo(T)
location: variable item of type T
where T is a type-variable:
T extends Comparable<? super T> declared in class BST
Here is my code, what am I doing wrong?
import java.util.List;
import java.util.ArrayList;
import java.util.*;
import java.io.*;
public class BST<T extends Comparable<? super T>> implements BSTInterface<T>
{
private BinaryNode<T> root;
private int numberOfItems;
public List<T> preOrder = new ArrayList<T>();
public List<T> inOrder = new ArrayList<T>();
public List<T> postOrder = new ArrayList<T>();
public BST()
{
root = null;
numberOfItems = 0;
}
public BST(T rootData)
{
root = new BinaryNode<T>(rootData);
numberOfItems = 1;
}
public BST(T rootData, BST<T> leftTree, BST<T> rightTree)
{
root = new BinaryNode<T>(rootData);
numberOfItems = 1;
root.left = leftTree.root;
root.right = rightTree.root;
}
public void setTree(T rootData)
{
root = new BinaryNode<T>(rootData);
}
public boolean contains(T item)
{
if (root.data.equals(item))
return true;
else
{
if (item.CompareTo(root.data) > 0)
{
root = root.left;
return contains(item);
}
else if (item.CompareTo(root.data) < 0)
{
root = root.right;
return contains(item);
}
else
return false;
}
}
public void add(T newItem)
{
if (root == null)
{
root = new BinaryNode<T>(newItem);
numberOfItems++;
}
if (newItem.equals(root.data))
return;
if (newItem.CompareTo(root.data) < 0)
{
root = root.left;
add(newItem);
}
if (newItem.CompareTo(root.data) > 0)
{
root = root.right;
add(newItem);
}
}
This isn't c# :p
item.CompareTo()
change to:
item.compareTo()
compareTo is coming from the Comparable interface.
[Comparable<T>][1] has following signature
int compareTo(T o)
Compares this object with the specified object for order.
But you are using CompareTo() Please correct the case and than try
Its compareTo() not CompareTo() // you are using capital C which is wrong
int java.lang.Comparable.compareTo(? super T o):-
Compares this object with the specified object for order. Returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.
The implementor must ensure sgn(x.compareTo(y)) == -sgn(y.compareTo(x)) for all x and y. (This implies that x.compareTo(y) must throw an exception iff y.compareTo(x) throws an exception.)
The implementor must also ensure that the relation is transitive: (x.compareTo(y)>0 && y.compareTo(z)>0) implies x.compareTo(z)>0.
Finally, the implementor must ensure that x.compareTo(y)==0 implies that sgn(x.compareTo(z)) == sgn(y.compareTo(z)), for all z.
It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y)). Generally speaking, any class that implements the Comparable interface and violates this condition should clearly indicate this fact. The recommended language is "Note: this class has a natural ordering that is inconsistent with equals."
In the foregoing description, the notation sgn(expression) designates the mathematical signum function, which is defined to return one of -1, 0, or 1 according to whether the value of expression is negative, zero or positive.
Parameters:
o - the object to be compared.
Returns:
a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.
Throws:
ClassCastException - if the specified object's type prevents it from being compared to this object.
If you are implementing java.lang.Comparable, then the method should be called compareTo(), not CompareTo().
To avoid this type of error, it is advisable to use the #Override annotation in front of your methods. This way Eclipse will tell you that you are not overriding an existing method.

Comparing the values of two generic Numbers

I want to compare to variables, both of type T extends Number. Now I want to know which of the two variables is greater than the other or equal. Unfortunately I don't know the exact type yet, I only know that it will be a subtype of java.lang.Number. How can I do that?
EDIT: I tried another workaround using TreeSets, which actually worked with natural ordering (of course it works, all subclasses of Number implement Comparable except for AtomicInteger and AtomicLong). Thus I'll lose duplicate values. When using Lists, Collection.sort() will not accept my list due to bound mismatchs. Very unsatisfactory.
This should work for all classes that extend Number, and are Comparable to themselves. By adding the & Comparable you allow to remove all the type checks and provides runtime type checks and error throwing for free when compared to Sarmun answer.
class NumberComparator<T extends Number & Comparable> implements Comparator<T> {
public int compare( T a, T b ) throws ClassCastException {
return a.compareTo( b );
}
}
A working (but brittle) solution is something like this:
class NumberComparator implements Comparator<Number> {
public int compare(Number a, Number b){
return new BigDecimal(a.toString()).compareTo(new BigDecimal(b.toString()));
}
}
It's still not great, though, since it counts on toString returning a value parsable by BigDecimal (which the standard Java Number classes do, but which the Number contract doesn't demand).
Edit, seven years later: As pointed out in the comments, there are (at least?) three special cases toString can produce that you need to take into regard:
Infinity, which is greater than everything, except itself to which it is equal
-Infinity, which is less than everything, except itself to which it is equal
NaN, which is extremely hairy/impossible to compare since all comparisons with NaN result in false, including checking equality with itself.
After having asked a similar question and studying the answers here, I came up with the following. I think it is more efficient and more robust than the solution given by gustafc:
public int compare(Number x, Number y) {
if (isSpecial(x) || isSpecial(y))
return Double.compare(x.doubleValue(), y.doubleValue());
else
return toBigDecimal(x).compareTo(toBigDecimal(y));
}
private static boolean isSpecial(Number x) {
var specialDouble = x instanceof Double d
&& (Double.isNaN(d) || Double.isInfinite(d));
var specialFloat = x instanceof Float f
&& (Float.isNaN(f) || Float.isInfinite(f));
return specialDouble || specialFloat;
}
private static BigDecimal toBigDecimal(Number number) {
if (number instanceof BigDecimal d)
return d;
if (number instanceof BigInteger i)
return new BigDecimal(i);
if (number instanceof Byte || number instanceof Short
|| number instanceof Integer || number instanceof Long)
return new BigDecimal(number.longValue());
if (number instanceof Float || number instanceof Double)
return new BigDecimal(number.doubleValue());
try {
return new BigDecimal(number.toString());
} catch(NumberFormatException e) {
throw new RuntimeException("The given number (\"" + number + "\" of class " + number.getClass().getName() + ") does not have a parsable string representation", e);
}
}
One solution that might work for you is to work not with T extends Number but with T extends Number & Comparable. This type means: "T can only be set to types that implements both the interfaces."
That allows you to write code that works with all comparable numbers. Statically typed and elegant.
This is the same solution that BennyBoy proposes, but it works with all kinds of methods, not only with comparator classes.
public static <T extends Number & Comparable<T>> void compfunc(T n1, T n2) {
if (n1.compareTo(n2) > 0) System.out.println("n1 is bigger");
}
public void test() {
compfunc(2, 1); // Works with Integer.
compfunc(2.0, 1.0); // And all other types that are subtypes of both Number and Comparable.
compfunc(2, 1.0); // Compilation error! Different types.
compfunc(new AtomicInteger(1), new AtomicInteger(2)); // Compilation error! Not subtype of Comparable
}
The most "generic" Java primitive number is double, so using simply
a.doubleValue() > b.doubleValue()
should be enough in most cases, but... there are subtle issues here when converting numbers to double. For example the following is possible with BigInteger:
BigInteger a = new BigInteger("9999999999999992");
BigInteger b = new BigInteger("9999999999999991");
System.out.println(a.doubleValue() > b.doubleValue());
System.out.println(a.doubleValue() == b.doubleValue());
results in:
false
true
Although I expect this to be very extreme case this is possible. And no - there is no generic 100% accurate way. Number interface have no method like exactValue() converting to some type able to represent number in perfect way without loosing any information.
Actually having such perfect numbers is impossible in general - for example representing number Pi is impossible using any arithmetic using finite space.
What about this one? Definitely not nice, but it deals with all necessary cases mentioned.
public class SimpleNumberComparator implements Comparator<Number>
{
#Override
public int compare(Number o1, Number o2)
{
if(o1 instanceof Short && o2 instanceof Short)
{
return ((Short) o1).compareTo((Short) o2);
}
else if(o1 instanceof Long && o2 instanceof Long)
{
return ((Long) o1).compareTo((Long) o2);
}
else if(o1 instanceof Integer && o2 instanceof Integer)
{
return ((Integer) o1).compareTo((Integer) o2);
}
else if(o1 instanceof Float && o2 instanceof Float)
{
return ((Float) o1).compareTo((Float) o2);
}
else if(o1 instanceof Double && o2 instanceof Double)
{
return ((Double) o1).compareTo((Double) o2);
}
else if(o1 instanceof Byte && o2 instanceof Byte)
{
return ((Byte) o1).compareTo((Byte) o2);
}
else if(o1 instanceof BigInteger && o2 instanceof BigInteger)
{
return ((BigInteger) o1).compareTo((BigInteger) o2);
}
else if(o1 instanceof BigDecimal && o2 instanceof BigDecimal)
{
return ((BigDecimal) o1).compareTo((BigDecimal) o2);
}
else
{
throw new RuntimeException("Ooopps!");
}
}
}
This should work for all classes that extend Number, and are Comparable to themselves.
class NumberComparator<T extends Number> implements Comparator<T> {
public int compare(T a, T b){
if (a instanceof Comparable)
if (a.getClass().equals(b.getClass()))
return ((Comparable<T>)a).compareTo(b);
throw new UnsupportedOperationException();
}
}
if(yourNumber instanceof Double) {
boolean greaterThanOtherNumber = yourNumber.doubleValue() > otherNumber.doubleValue();
// [...]
}
Note: The instanceof check isn't necessarily needed - depends on how exactly you want to compare them. You could of course simply always use .doubleValue(), as every Number should provide the methods listed here.
Edit: As stated in the comments, you will (always) have to check for BigDecimal and friends. But they provide a .compareTo() method:
if(yourNumber instanceof BigDecimal && otherNumber instanceof BigDecimal) {
boolean greaterThanOtherNumber = ((BigDecimal)yourNumber).compareTo((BigDecimal)otherNumber) > 0;
}
You can simply use Number's doubleValue() method to compare them; however you may find the results are not accurate enough for your needs.
Let's assume that you have some method like:
public <T extends Number> T max (T a, T b) {
...
//return maximum of a and b
}
If you know that there are only integers, longs and doubles can be passed as parameters then you can change method signature to:
public <T extends Number> T max(double a, double b) {
return (T)Math.max (a, b);
}
This will work for byte, short, integer, long and double.
If you presume that BigInteger's or BigDecimal's or mix of floats and doubles can be passed then you cannot create one common method to compare all these types of parameters.
If your Number instances are never Atomic (ie AtomicInteger) then you can do something like:
private Integer compare(Number n1, Number n2) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
Class<? extends Number> n1Class = n1.getClass();
if (n1Class.isInstance(n2)) {
Method compareTo = n1Class.getMethod("compareTo", n1Class);
return (Integer) compareTo.invoke(n1, n2);
}
return -23;
}
This is since all non-Atomic Numbers implement Comparable
EDIT:
This is costly due to reflection: I know
EDIT 2:
This of course does not take of a case in which you want to compare decimals to ints or some such...
EDIT 3:
This assumes that there are no custom-defined descendants of Number that do not implement Comparable (thanks #DJClayworth)
In my use case, I was looking for a general Comparator that works with the autoboxed primitives (64 bit max precision), not arbitrary precision types like BigInteger and BigDecimal. Here's a first shot at it..
public class PrimitiveComparator implements Comparator<Number> {
#Override
public int compare(Number a, Number b) {
if (a == b)
return 0;
double aD = a.doubleValue();
double bD = b.doubleValue();
int comp = Double.compare(aD, bD);
if (comp == 0 && inLongBounds(aD))
comp = Long.compare(a.longValue(), b.longValue());
return comp;
}
private boolean inLongBounds(double value) {
return
Double.compare(value, Long.MAX_VALUE) <= 0 &&
Double.compare(value, Long.MIN_VALUE) >= 0;
}
}
The objective is to be able to compare mixed types (e.g. Floats against Longs). This should also work with those AtomicXxx types (or any hand rolled Number subclass that uses no more than 64 bits).
In this ordering, btw, Double.NaN > Double.POSITVE_INFINITY > { everything else }.

Java Generics and Infinity (Comparable)

With the type Integer you can do this:
int lowest = Integer.MIN_VALUE;
What can I do if I use generics?
K lowest = <...>;
I need this in order to implement something similar to a PriorityQueue.
I have access to a node I want to remove from the queue, but it is not the min.
1. I need to make it the min by decreasing the key of that node,
2. And then remove the min.
I am stuck on the first step. The only thing I can do is set the key of the node to the current min. Not sure it is enough.
There is no generic form of MIN_VALUE or MAX_VALUE for all Comparable types.
Think about a Time class that implements comparable. There is no MAX_VALUE for Time even though it is Comparable.
I am trying to imagine what scenario would require such behavior. This is the best I can come up with...
WARNING: This code is dangerous. Please be merciful to me for posting such an abomination. It is only a proof of concept.
public class Lowest<K> implements Comparable<K> {
public int compareTo(K other) {
return -1;
}
}
And then...
public class Test {
public <K extends Comparable<K>> K findMaximum(List<K> values) throws Exception {
K lowest = (K) new Lowest<K>(); /// XXX DANGER! Losing compile-time safety!!!
K maximum = lowest;
for (K value : values) {
if (maximum.compareTo(value) < 0) {
maximum = value;
}
}
if (maximum == lowest) {
throw new Exception("Could not find a maximum value");
} else {
return maximum;
}
}
}
This doesn't make any sense...
Given that you don't know what K is at that point, (i.e. You're implementing it generically... duh!) you can't specify a min/max bound for it.
in a case where K could be a int, long, string OR object, you couldn't sensibly guess to use
Integer.MIN_VALUE, "" OR NULL.
I guess what you're looking for is a K.MIN_VALUE_OF_EVENTUAL_TYPE but that doesn't exist.
You can make a wrapper class that "adds" a minimum and maximum value to all types. It just has two static instances that represent minimum and maximum, and then other instances wrap some other value of some type. When we do a comparison, we check if one of the things is the minimum or maximum, and return the proper result; and otherwise we just do the same comparison as the underlying type. Something like this:
class Extended<T extends Comparable<? super T>> implements Comparable<Extended<T>> {
private Extended() { }
private static Extended min = new Extended();
private static Extended max = new Extended();
#SuppressWarnings("unchecked")
public static <T extends Comparable<? super T>> Extended<T> getMin() {
return (Extended<T>)min;
}
#SuppressWarnings("unchecked")
public static <T extends Comparable<? super T>> Extended<T> getMax() {
return (Extended<T>)max;
}
public T value;
public Extended(T x) { value = x; }
public int compareTo(Extended<T> other) {
if (this == other) return 0;
else if (this == min || other == max) return -1;
else if (this == max || other == min) return 1;
else return this.value.compareTo(other.value);
}
}
Consider not making K a generic, but using an interface that wraps the primitive wrapper (a double wrapper!).
import java.util.HashMap;
public class NodeWrapper<K extends Comparable<K>> implements Comparable<NodeWrapper<K>> {
private static HashMap<Class, NodeWrapper> minVals = new HashMap<Class, NodeWrapper>();
private K value;
private NodeWrapper() {
super();
}
public NodeWrapper(K value, Class<K> clazz) {
super();
this.value = value;
if (minVals.get(clazz)==null) {
minVals.put(clazz, new NodeWrapper<K>());
}
}
public K getValue() {
return value;
}
public static NodeWrapper getMinValue(Class clazz){
return minVals.get(clazz);
}
public void setValue(K value) {
this.value = value;
}
#Override
public int compareTo(NodeWrapper<K> o) {
NodeWrapper min = minVals.get(this.getClass());
if (this==min && o==min) {
return 0;
} else if (this==min){
return -1;
} else if (o==min){
return 1;
} else {
return this.value.compareTo(o.value);
}
}
}
Briefly, the idea is that whenever a new class is instantiated, a minimum value is created and put into a static hashmap that stores the minimum values for each class. (In fact, these values are NOTHING at all, just a sentinel object, but since we will use object equality to determine if something is the min value, this is no problem at all.) All that's necessary is that the wrapped object be comparable to other instances of itself in general.
One drawback is that when you call getMinValue you will have compiler warnings, since the return type will have no generic information. There may be a more elegant way around this, but I can't think of it right now.
This general idea might be rather nice overall. However, I should really stress: this will absolutely break if you try it with any polymorphism or any mixing of mutually comparable classes. Longs and Integers in the same tree will completely destroy you.
er... what's the problem again?
PriorityQueue, like all Collections, allows you to use an instance of an object to remove it from the collection.
Uh doesn't this depend on what type K is?
The point of Generics is that K can be any type (or any subclass of a certain type); in order to be able to call methods on K or access properties of it, you need to restrict it's type bounds with wildcards.
just because an object is a comparable does not mean it has to have a minimum value. The reason int has a min value of -(2^(31)) is because you need 1 bit for a sign, so 2^31 is the largest (or smallest) possible integer that can be stored. For things like string, it does not make any sense since there is no largest/smallest possible string, it is memory bound.
You might have to create an interface "IInfinity", and have K extends IInfinity, and IInfinity to have a method "getInfinityValue()", and then wrap/extend Integer, Double, BigDecimal, etc in a class that implements IInfinity ... and ugh!
Basically you want any type K to implement some static functions say lowest and highest which obey the standard mathematical properties.
I assume that for this sense of lowest (or highest) to be usable you would want any Comparable object to have these methods. (or static fields). If you are only interested in your own custom objects, the way to do this would be to have everything inherit from an abstract data type which declared static fields for MINVALUE and MAX_VALUE and then your type varaibles would be . If you need this functionality for other classes you will need to cre4ate some sort of external hashmap which tracks these properties for different classes (but that would get pretty ugly)

Categories