How to Compare Values of Generic Types

How to compare values of generic types?

IComparable doesn't overload the >= operator. You should use

value.CompareTo(_minimumValue) >= 0

c# compare two generic values

You cannot use operators on generic types (except for foo == null which is special cased) unless you add where T : class to indicate it is a reference type (then foo == bar is legal)

Use EqualityComparer<T>.Default to do it for you. This will not work on types which only supply an operator overload for == without also either:

  • implement IEquatable<T>
  • overrides object.Equals()

In general implementing the == operator and not also doing at least one of these would be a very bad idea anyway so this is not likely to be an issue.

public bool IsDataChanged<T>()
{
T value1 = GetValue2;
T value2 = GetValue1();

return !EqualityComparer<T>.Default.Equals(value1 , value2);
}

If you do not restrict to IEquatable<T> then the EqualityComparer default fallback may cause boxing when used with value types if they do not implement IEquatable<T> (if you control the types which are being used this may not matter). I am assuming you were using =! for performance though so restricting to the Generic type will avoid accidental boxing via the Object.Equals(object) route.

Java how to compare two generic type parameters

The < and > operators can only be used with primitive types, and the Number class does not implement Comparable itself, so you can't use compareTo.

However if you add Comparable<T> as a type bound:

public class MyList<T extends Number & Comparable<T>> {
...
}

then you can use the compareTo method:

public T largest() {
boolean onFirstObj = true;
T largestVal = null;

for (T t : list) {
if (onFirstObj) {
largestVal = t;
onFirstObj = false;
} else {
if (t.compareTo(largestVal) > 0) {
largestVal = t;
}
}
}

return largestVal;
}

Java comparing generic types

You cannot overload operators in Java. The < operator only applies to primitive (or numeric) types, not reference types. Since T is a type variable that represents a reference type, you cannot use < on variables of type T. You have to use

if (item.compareTo(bn.item) < 0) 

check the value returned and decide to do what you wish with it.

You don't know what the type T will be but you know that it will be a type that implements Comparable and therefore implements the compareTo() method.

Comparing the values of two generic Numbers

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.

Java-How do I compare generic types?

Your line insert((T)input.next()); doesn't make sense - input.next() is a String, but you're casting it to a T even though T isn't associated with a real type at this point. When constructing a Tree a caller could, for instance, say new Tree<Integer> making that line, in essence, insert((Integer)input.next());, which is broken.

If your goal is for Tree to always contain Strings, just remove the generic T type from Tree and just use String. If you actually want to support arbitrary types you need to move the file-reading behavior out of the Tree constructor (e.g. into a static method that returns a Tree<String>).

For example:

public static Tree<String> readFromFile(Path file) throws FileNotFoundException {
try (Scanner input = new Scanner(file)) {
Tree<String> tree = new Tree<>();
while(input.hasNext()) {
tree.insert(input.next());
}
return tree;
}
}

Notice that I used Path instead of File, the try-with-resources pattern, and I don't suppress the exception, instead the caller (likely the main method) should handle the exception properly (likely by reporting the file doesn't exist and exiting). Alternatively adding a catch block like so:

catch (IOException e) {
throw new RuntimeException("Could not open " + file, e);
}

would avoid forcing callers to handle the exception.


Now that we've cleaned up the Tree type, your ordering question is likely simpler to answer. If you intend to order the elements as integers, convert the inputs to Integers, e.g.

public static Tree<Integer> readIntsFromFile(Path file) throws FileNotFoundException {
...
tree.insert(Integer.valueOf(input.next()));
...
}

This will order the tree based on the integer ordering, rather than the strings' lexicographic ordering. This is what I'd suggest you do. It's straightforward and does what you want.


If you really want a Tree<String> but you want to order them as if they were integers you need a custom Comparator, as you mention. You would then need to pass the Comparator into the Tree's constructor, and call comparator.compare(element, current.element) where you currently call element.compareTo(current.element).



Related Topics



Leave a reply



Submit