1

I have an ArrayList of object called Course and I'm trying to sort it in 2 ways, by courseID and course start time.

class Course implements Comparable<Course> {
    private int courseID;
    private String courseBeginTime;

    // implement the compareTo method defined in Comparable
    @Override
    public int compareTo(Course course) {
        if (getCourseID() > course.getCourseID()){
            return 1;
        } else if(getCourseID() < course.getCourseID()){
            return -1;
        } else {
            return 0;
        }       
    }

Then I have these comparators:

//implement the comparators
class IDSorter implements Comparator<Course> {
    public int compare(Course course1, Course course2) {
        return Integer.compare(course1.getCourseID(), course2.getCourseID());
    }
}

class startTimeSorter implements Comparator<Course> {
    public int compare(Course course1, Course course2) {
        return Integer.compare(Integer.parseInt(course1.getCourseBeginTime()),
                Integer.parseInt(course2.getCourseBeginTime()));
    }
}

I sort them in my main method like this:

Collections.sort(courseList, new IDSorter());
Collections.sort(student.getStudentSchedule(), new StartTimeSorter());

The code works, I can get the list sorted by ID or startTime.... but I don't understand why. In the Course class the compareTo method is only comparing getCourseID.

How is the StartTimeSorter, which needs to compare courseBeginTime working then?

How can I rewrite to make more sense?

rawr rang
  • 763
  • 2
  • 7
  • 24

4 Answers4

2

If a class implements Comparable, this is considered to be the natural ordering of this class. This ordering is used when you don't give an explicit Comparator to Collections.sort. That is why the single argument version of sort takes a List<T> where T extends Comparable<? super T>. The two argument versions take a List<T> with no restrictions on T and a Comparator<? super T>. So Course.compareTo is not used in your example.

Drunix
  • 3,313
  • 8
  • 28
  • 50
  • Could I have sorted it two different ways without using creating my own comparator then? I feel like its silly that I overrode the compareTo method even tho I don't need to use it, but the compiler warns me I need to implement it anyway. – rawr rang Mar 17 '14 at 09:15
  • Either IDSorter or implementing Comparable is redundant. The StartTimeSorter will still be necessary. I would stick to two Comparators if all orderings should be treated in a uniform way. – Drunix Mar 17 '14 at 09:19
  • So since I'm using my own comparator, what should I have written in my compareTo method then? Basically anything I write in there is meaningless and right now what I have in there is misleading at best. – rawr rang Mar 17 '14 at 09:28
  • Nothing if you don't want to have a natural ordering, just do not implement Comparable. It can be even dangerous if it is not consistent with equals (I guess this is not the case in your example, assuming courseIDs are unique). I have to admit that this also applies to Comparators. See http://stackoverflow.com/questions/12123960/what-does-comparison-being-consistent-with-equals-mean-what-can-possibly-happe – Drunix Mar 17 '14 at 09:32
1

There are two variants to Collections.sort method. One takes a single argument as a collection of Comparable objects. The other one takes two arguments: first is a collection second is a comparator. You used second variant. Hence your compareTo method is not used.

Hakan Serce
  • 11,198
  • 3
  • 29
  • 48
  • Gotcha, so I get basically the code in my compareTo method is not used. So in this case where I'm not using the compareTo, I still have to implement it otherwise the compiler warns me I need to implement it. As a standard practice, What code should I put in there then if I'm not using it? I have to return something for the compareTo method. – rawr rang Mar 17 '14 at 09:01
  • You don't need to implement it as you do not need to implement Comparable interface. – Hakan Serce Mar 17 '14 at 09:27
1

If you specify a Comparator in the Collections.sort method, it will take that into account, no matter even it the class implements Comparable. Try sorting without passing the Comparator in the sort method, you will see what you are expecting, i.e., the compareTo method kicks in.

Shiva Kumar
  • 3,111
  • 1
  • 26
  • 34
  • Thanks I understand now. So if I'm using my own Comparator, thenI'm not even using the compareTo method. Then what should I code into the compareTo method? I need to implement it since I declear Course implements Comparable – rawr rang Mar 17 '14 at 09:04
  • There are two ways to be able to compare your classes. One is to let the class implement Comparable, the other is to pass Comparator in the sort method of Collections. The latter is preferred because you are not binding only one comparision logic to the class, but can sort your class in multiple ways passing different comparator implementations – Shiva Kumar Mar 17 '14 at 09:39
0

I think your compareTo method just needs to be this:

@Override
public int compareTo(Course course) {
    if (getCourseID() > course.getCourseID()){
        return 1;
    } else if(getCourseID() < course.getCourseID()){
        return -1;
    } else {
        return Integer.compare(Integer.parseInt(getCourseBeginTime()),
            Integer.parseInt(course.getCourseBeginTime()));
    }       
}
Dan Temple
  • 2,736
  • 2
  • 22
  • 39