Reputation: 1403
I'm sorry, yet another one of those questions, but I can simply not understand what is going on here, or where I'm going wrong.
Overview: I have a ArrayList
containing multiple Movie
- Objects.Those have a date
, and a startingTime
. I'd like to sort them by the following conditions, priority as listed:
date
startingTime
But when doing so, I get the following error:
java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeHi(TimSort.java:864)
at java.util.TimSort.mergeAt(TimSort.java:481)
at java.util.TimSort.mergeForceCollapse(TimSort.java:422)
at java.util.TimSort.sort(TimSort.java:219)
at java.util.TimSort.sort(TimSort.java:169)
at java.util.Arrays.sort(Arrays.java:2010)
at java.util.Collections.sort(Collections.java:1883)
at org.pbdevelopement.cineapp.MainActivity.sortByStartingTime(MainActivity.java:208)
What I've got:
I have the same thing going on in a JavaFX Project, but there I sort using ArrayList.sort()
rather then Collections.sort()
. I needed to convert to the Collections.sort()
as apparently Android does not support the ArrayList.sort()
Method yet.
This is the method that initiates the sorting and defines the Comperator
:
private ArrayList<Movie> sortByStartingTime(ArrayList<Movie> list) {
Collections.sort(list, new Comparator<Movie>() { //This line is MainActivity.java: 208 ;)
@Override
public int compare(Movie o1, Movie o2) {
int comparison = o1.getDate().compareTo(o2.getDate());
if (comparison == 0) {
return o1.getStartingTime().compareTo(o2.getStartingTime());
}
return comparison;
}
});
return list;
}
As you can see, I compare the two date
from the movies, and if they are equal, I continue to compare the starting times.
Here are the two compare()
Methods from my DateKeeper
and TimeKeeper
classes (I should maybe admit that they are self written):
public int compareTo(DateKeeper toCompare) {
Calendar startDate = getAsCalendar();
Calendar endDate = toCompare.getAsCalendar();
long diff = endDate.getTimeInMillis() - startDate.getTimeInMillis();//in Milli seconds
return (int) (diff / (1000 * 60 * 60 * 24));
}
I am not returning either -1
,0
or 1
as I would like to use this method for the difference between two dates as well. I've read up on the compare
method and found this should not be a problem.
public int compareTo(TimeKeeper toCompare) {
int toReturn = Integer.compare(this.getValue(), toCompare.getValue());
return toReturn;
}
getValue()
simply returns what is known as MINUTES_OF_DAY
.
I don't understand how this violates the method contract. For what I know the Comperator
is transitive (or is it not?) reflexive, and symmetric. So why am I getting this error message?
Upvotes: 0
Views: 361
Reputation: 2494
Your problem is that you divide by number of milliseconds in the day after you subtract.This may lead to two shows that may be <24 hours apart but on different days to show as on the same day. Try:
public int compareTo(DateKeeper toCompare) {
Calendar startDate = getAsCalendar();
Calendar endDate = toCompare.getAsCalendar();
long diff = (endDate.getTimeInMillis()/ (1000 * 60 * 60 * 24)) - (startDate.getTimeInMillis()/ (1000 * 60 * 60 * 24));//in Milli seconds
return (int) diff;
}
or set the time on both calendar objects to be midnight
Upvotes: 2