Java override compareTo, Long - java

I have a class that implements the Comparable interface. In this class I need to override compareTo method in order to sort objects by Long values.
What I don't know is how to perform is the comparison of the Long type.
I get error when trying to check if value is greater than or less than another Long value.
I know Long is the object of long, but have no idea how to compare two Long's.
Code sample:
public int compareTo(MyEntry<K, V> object) {
if (this.value < object.value)
return -1;
if (this.value.equals(object.value))
return 0;
return 1;
}
Error message:
operator < cannot be applied to V,V
if (this.value < object.value)
^
V, V is Long, Long

Your problem is that MyEntry<K, V> doesn't tell the compiler what type of Object you're trying to compare. It doesn't know that you're comparing Long values. The best way to do this is to not worry about what type of Object you're comparing (assuming your object implements Comparable) by just using
return this.value.compareTo(object.value);
but if you want to do it manually for some reason, do this:
public int compareTo(MyEntry<K, V> object) {
if ((Long) this.value < (Long) object.value)
return -1;
if (this.value.equals(object.value))
return 0;
return 1;
}

Long l1 = new Long(3);
Long l2 = new Long(2);
return l1.compareTo(l2);
Simple no?

It would look something like this:
#Override
public int compareTo(MyEntry<K, V> object) {
if (object == null) {
throw new NullPointerException("Null parameter");
} else if (!this.getClass().equals(object.getClass())) {
throw new ClassCastException("Possible ClassLoader issue.");
} else {
return this.longValue.compareTo(object.longValue);
}
}
Coincidentally, we recently did a tutorial on comparisons in Java. Maybe it can help you.

Cast long to Long, then use compareTo method of Long.
Java is well structured, nearly all sortable Class has compareTo method.
This is a good Java practice.
#Override
public int compare(long t1, long t2) {
return Long.valueOf(t1).compareTo(t2);
}

Use longValue() method for comparison of long values.
eg:-
Long id1 = obj.getId();
Long id2 = obj1.getId();
if (id1.longValue() <= id2.longValue()) {
Sysout.......
}
assertTrue(id1.longValue() == id2.longValue())

The long compareTo command might help. The compareTo method returns an integer value to give you an answer as to whether the longs are equal, greater than, or less than each other.
Long l1 = new Long(63255);
Long l2 = new Long(71678);
int returnVal = l1.compareTo(l2);
if(returnVal > 0) {
System.out.println("l1 is greater than l2");
}
else if(returnVal < 0) {
System.out.println("l1 is less than l2");
}
else {
System.out.println("l1 is equal to l2");
}

Related

Java Comparator throws Illegal Argument Exception

I get this error:
Exception in thread "Thread-3" java.lang.IllegalArgumentException: Comparison method violates its general contract!
When I try to run this comparator for my entity system in Java:
private Comparator<Entity> spriteSorter = new Comparator<Entity>() {
public int compare(Entity e0, Entity e1) {
if (e1.position.getX() <= e0.position.getX())
return +1;
if (e1.position.getY() >= e0.position.getY())
return -1;
return 0;
}
};
Here is the implementation:
private void sortAndRender(Bitmap b, Vec2 offset, ArrayList<Entity> l) {
Collections.sort(l, spriteSorter);
for (int i = 0; i < l.size(); i++) {
l.get(i).render(b, offset);
}
}
This issue only really began occurring when I was displaying large amounts of entities on the screen. What is going on here?
Your comparator is just plain wrong. Better would be something like
if (e1.position.getX() != e0.position.getX())
return Integer.compare(e1.position.getX(), e0.position.getX());
if (e1.position.getY() != e0.position.getY())
return Integer.compare(e1.position.getY(), e0.position.getY());
return 0;
While #Louis beat me to it for the most part, to elaborate and possibly clarify...
Your Compare method must be fairly "stable" and complete. Yours will return 0, "equals" for a lot of cases where the X and Y are different.
I'd rewrite it as
int result = Integer.compare(e1.position.getX(), e0.position.getX());
if (result == 0)
result = Integer.compare(e1.position.getY(), e0.position.getY());
... if you have more to compare, add more if (result == 0) blah blah here...
return result;
As for "stable", let's say you have two points, a = 4,2 and b = 2,4
When you compare a to b, you get 0
But when you compare b to a, you get 1.
This is "illegal" in a comparator. a.compareTo(b) should equal -b.compareTo(a)
Haha, issue was i was for some reason moving them up on the list based on x position, and down the list based on y position??!?!? This was a really silly mistake from me

How to sort arrayList<Object> by object attribute long in Java

I have class (JavaBean if you want to call it like that)
class Tweet{
private millis; //number of millis since 1970
//other attributes and getters and setters, but i want to sort onlny by millis
public long getMillis() {
return millis;
}
}
Comparator should be probably look simillar to this:
class TweetComparator implements Comparator {
#Override
public int compare(Tweet t1, Tweet t2) {
//something
//this doesn't work
//return t2.getMillis().compareTo(t1.getMillis());
return ??;//what should be here?
}
}
This will be in program
List<Tweet> tweets = new ArrayList<Tweet>();
tweets.add(...); //just fill the list
//i need newest (with hightest millis value first) so I probably need to call reverse order
Collection.reverse(tweets)
Collection.sort(tweets, new TweetComparator());
I found some references here
and here. But I don't know how to complete my code.
Your comparator should look similar to this
class TweetComparator implements Comparator<Tweet> {
#Override
public int compare(Tweet t1, Tweet t2) {
return Long.compare(t1.getMillis(), t2.getMillis());
}
}
note that static int Long.compare is since Java 7
Compare method Returns:
a negative integer, zero, or a positive integer as the first argument is less than, equal to, >or greater than the second.
Logic -
if t1.millis > t2.millis
return -1;
else if t1.millis < t2.millis
return +1;
Code -
class TweetComparator implements Comparator<Tweet> {
#Override
public int compare(Tweet t1, Tweet t2) {
if(s1.i>s2.i)
return -1;
else if(s1.i<s2.i)
return +1;
return 0;
}
}
Try This:
#Override
public int compare(Tweet t1, Tweet t2) {
return t1.getMillis().compareTo(t2.getMillis());
}
Change you mills varaible to Long if you want to use inbuilt compareTo method of Long class.
Otherwise inside compare method,compare your millis from t1 and t2 like below.
long t1Val = t1.getMillis();
long t2Val = t2.getMillis();
return (t1Val<t2Val? -1 : (t1Val ==t2Val? 0 : 1));
(Directly from original Long class)

compare more field of a object in compareTo

I'd compare more than one only field of a object using the compareTo method. Is it possible?
for istance:
public int compareTo(Object o) {
return field.compareTo(o.field);
}
I create this method to sort a collection. Obviously my object has to implement Comparable interface.
I'm guessing if is possible to compare not only one field in the same method compareTo.
Yes, it's possible. If the result of comparing the first field returns zero, then return the result of comparing the second field.
public int compareTo(SomeClass o) {
int result = field1.compareTo(o.field1);
if ( result == 0 ) {
result = field2.compareTo(o.field2);
}
return result;
}
This gets cumbersome fairly quickly, which is why Guava provides a ComparisonChain. Example use:
public int compareTo(SomeClass o) {
return ComparisonChain.start()
.compare(field1, o.field1)
.compare(field2, o.field2)
.result();
}
Yes, it's possible, for example like so:
public int compareTo(MyClass o){
int ret = field1.compareTo(o.field1);
if (ret != 0) return ret;
ret = field2.compareTo(o.field2);
if (ret != 0) return ret;
...
return fieldN.compareTo(o.fieldN);
}
You can certainly factor in other fields when comparing, but there's typically some order of precedence, just like sorting alphabetically only looks at the second letter if the first is the same:
public int compareTo(Object o){
int comparison = field.compareTo(o.field);
if (comparison != 0)
return comparison;
comparison = field2.compareTo(o.field2);
if (comparison != 0)
return comparison;
//etc...
}
sure you can.
however you must define the rule of comparison .
e.g.
you have
objectA{a=1;b=2;c=3}
objectB{a=20;b=1;c=6}
in your compareTo(Object o) method, you could compare this.fields with o.fields. you can even compare this.a to o.c if you really need. point is you have to define the rule, in which case objectA < objectB. etc..
Sure. Here's a relatively concise way of doing it.
public int compareTo(MyClass other) {
return
a!=other.a ? Integer.compare(a, other.a) :
b!=other.b ? Integer.compare(b, other.b) :
Integer.compare(c, other.c);
}
(Integer.compare is from Java SE 7, but the implementation isn't difficult. Assumes int fields a, b, c, but is essentially the same for any field types you can compare.)
public int compareTo(Object o){
int res = field.compareTo(o.field);
if(res==0)
res=field1.compareTo(o.field1);
return res;
}
should work
You can do it any of following ways:
public int compareTo(Object o)
{
return (field.compareTo(o.field)==1 && field2.compareTo(o.field2)==0)? 0 : 1;
}
OR
public int compareTo(Object o)
{
// add various if-else blocks
// OR
// call a separate method
}

Comparison operators in generic heap

For my data structures class our homework is to create a generic heap ADT. In the siftUp() method I need to do comparison and if the parent is smaller I need to do a swap. The problem I am having is that the comparison operators are not valid on generic types. I believe I need to use the Comparable interface but from what I read it’s not a good idea to use with Arrays. I have also search this site and I have found good information that relates to this post none of them helped me find the solution
I removed some of the code that wasn’t relevant
Thanks
public class HeapQueue<E> implements Cloneable {
private int highest;
private Integer manyItems;
private E[] data;
public HeapQueue(int a_highest) {
data = (E[]) new Object[10];
highest = a_highest;
}
public void add(E item, int priority) {
// check to see is priority value is within range
if(priority < 0 || priority > highest) {
throw new IllegalArgumentException
("Priority value is out of range: " + priority);
}
// increase the heaps capacity if array is out of space
if(manyItems == data.length)
ensureCapacity();
manyItems++;
data[manyItems - 1] = item;
siftUp(manyItems - 1);
}
private void siftUp(int nodeIndex) {
int parentIndex;
E tmp;
if (nodeIndex != 0) {
parentIndex = parent(nodeIndex);
if (data[parentIndex] < data[nodeIndex]) { <-- problem ****
tmp = data[parentIndex];
data[parentIndex] = data[nodeIndex];
data[nodeIndex] = tmp;
siftUp(parentIndex);
}
}
}
private int parent(int nodeIndex) {
return (nodeIndex - 1) / 2;
}
}
Technically you're using the comparable interface on on item, not an array. One item in the array specifically. I think the best solution here is to accept, in the constructor, a Comparator that the user can pass to compare his generic objects.
Comparator<E> comparator;
public HeapQueue(int a_highest, Comparator<E> compare)
{
this.comparator = compare;
Then, you would store that comparator in a member function and use
if (comparator.compare(data[parentIndex],data[nodeIndex]) < 0)
In place of the less than operator.
If I am reading this right, E simply needs to extend Comparable and then your problem line becomes...
if (data[parentIndex].compareTo(ata[nodeIndex]) < 0)
This is not breaking any bet-practice rules that I know of.

Treeset.contains() problem

So I've been struggling with a problem for a while now, figured I might as well ask for help here.
I'm adding Ticket objects to a TreeSet, Ticket implements Comparable and has overridden equals(), hashCode() and CompareTo() methods. I need to check if an object is already in the TreeSet using contains(). Now after adding 2 elements to the set it all checks out fine, yet after adding a third it gets messed up.
running this little piece of code after adding a third element to the TreeSet, Ticket temp2 is the object I'm checking for(verkoopLijst).
Ticket temp2 = new Ticket(boeking, TicketType.STANDAARD, 1,1);
System.out.println(verkoop.getVerkoopLijst().first().hashCode());
System.out.println(temp2.hashCode());
System.out.println(verkoop.getVerkoopLijst().first().equals(temp2));
System.out.println(verkoop.getVerkoopLijst().first().compareTo(temp2));
System.out.println(verkoop.getVerkoopLijst().contains(temp2));
returns this:
22106622
22106622
true
0
false
Now my question would be how this is even possible?
Edit:
public class Ticket implements Comparable{
private int rijNr, stoelNr;
private TicketType ticketType;
private Boeking boeking;
public Ticket(Boeking boeking, TicketType ticketType, int rijNr, int stoelNr){
//setters
}
#Override
public int hashCode(){
return boeking.getBoekingDatum().hashCode();
}
#Override
#SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
public boolean equals(Object o){
Ticket t = (Ticket) o;
if(this.boeking.equals(t.getBoeking())
&&
this.rijNr == t.getRijNr() && this.stoelNr == t.getStoelNr()
&&
this.ticketType.equals(t.getTicketType()))
{
return true;
}
else return false;
}
/*I adjusted compareTo this way because I need to make sure there are no duplicate Tickets in my treeset. Treeset seems to call CompareTo() to check for equality before adding an object to the set, instead of equals().
*/
#Override
public int compareTo(Object o) {
int output = 0;
if (boeking.compareTo(((Ticket) o).getBoeking())==0)
{
if(this.equals(o))
{
return output;
}
else return 1;
}
else output = boeking.compareTo(((Ticket) o).getBoeking());
return output;
}
//Getters & Setters
On compareTo contract
The problem is in your compareTo. Here's an excerpt from the documentation:
Implementor must ensure sgn(x.compareTo(y)) == -sgn(y.compareTo(x)) for all x and y.
Your original code is reproduced here for reference:
// original compareTo implementation with bug marked
#Override
public int compareTo(Object o) {
int output = 0;
if (boeking.compareTo(((Ticket) o).getBoeking())==0)
{
if(this.equals(o))
{
return output;
}
else return 1; // BUG!!!! See explanation below!
}
else output = boeking.compareTo(((Ticket) o).getBoeking());
return output;
}
Why is the return 1; a bug? Consider the following scenario:
Given Ticket t1, t2
Given t1.boeking.compareTo(t2.boeking) == 0
Given t1.equals(t2) return false
Now we have both of the following:
t1.compareTo(t2) returns 1
t2.compareTo(t1) returns 1
That last consequence is a violation of the compareTo contract.
Fixing the problem
First and foremost, you should have taken advantage of the fact that Comparable<T> is a parameterizable generic type. That is, instead of:
// original declaration; uses raw type!
public class Ticket implements Comparable
it'd be much more appropriate to instead declare something like this:
// improved declaration! uses parameterized Comparable<T>
public class Ticket implements Comparable<Ticket>
Now we can write our compareTo(Ticket) (no longer compareTo(Object)). There are many ways to rewrite this, but here's a rather simplistic one that works:
#Override public int compareTo(Ticket t) {
int v;
v = this.boeking.compareTo(t.boeking);
if (v != 0) return v;
v = compareInt(this.rijNr, t.rijNr);
if (v != 0) return v;
v = compareInt(this.stoelNr, t.stoelNr);
if (v != 0) return v;
v = compareInt(this.ticketType, t.ticketType);
if (v != 0) return v;
return 0;
}
private static int compareInt(int i1, int i2) {
if (i1 < i2) {
return -1;
} else if (i1 > i2) {
return +1;
} else {
return 0;
}
}
Now we can also define equals(Object) in terms of compareTo(Ticket) instead of the other way around:
#Override public boolean equals(Object o) {
return (o instanceof Ticket) && (this.compareTo((Ticket) o) == 0);
}
Note the structure of the compareTo: it has multiple return statements, but in fact, the flow of logic is quite readable. Note also how the priority of the sorting criteria is explicit, and easily reorderable should you have different priorities in mind.
Related questions
What is a raw type and why shouldn't we use it?
How to sort an array or ArrayList ASC first by x and then by y?
Should a function have only one return statement?
This could happen if your compareTo method isn't consistent. I.e. if a.compareTo(b) > 0, then b.compareTo(a) must be < 0. And if a.compareTo(b) > 0 and b.compareTo(c) > 0, then a.compareTo(c) must be > 0. If those aren't true, TreeSet can get all confused.
Firstly, if you are using a TreeSet, the actual behavior of your hashCode methods won't affect the results. TreeSet does not rely on hashing.
Really we need to see more code; e.g. the actual implementations of the equals and compareTo methods, and the code that instantiates the TreeSet.
However, if I was to guess, it would be that you have overloaded the equals method by declaring it with the signature boolean equals(Ticket other). That would lead to the behavior that you are seeing. To get the required behavior, you must override the method; e.g.
#Override
public boolean equals(Object other) { ...
(It is a good idea to put in the #Override annotation to make it clear that the method overrides a method in the superclass, or implements a method in an interface. If your method isn't actually an override, then you'll get a compilation error ... which would be a good thing.)
EDIT
Based on the code that you have added to the question, the problem is not overload vs override. (As I said, I was only guessing ...)
It is most likely that the compareTo and equals are incorrect. It is still not entirely clear exactly where the bug is because the semantics of both methods depends on the compareTo and equals methods of the Boeking class.
The first if statement of the Ticket.compareTo looks highly suspicious. It looks like the return 1; could cause t1.compareTo(t2) and t2.compareTo(t1) to both return 1 for some tickets t1 and t2 ... and that would definitely be wrong.

Categories

Resources