6

I have a object called project, I want to sort this project by 2 of its fields:

First: by Date(Gregorian Callander); Second: by Name(String);

I want to sort the project by date form new to old. The only way I know to do this is to reverse the collection. However I want to sort the project with same date on name(alphabetically), where reverse also reverses this part of the sort.

Is there a way to reverse only part of the sort method, or any other way to get this sorted first by a date(reverse) and then a string(normal order a-z) ?

At the moment I am overriding the object compareTo method like so:

   @Override
public int compareTo(Project project) {
    int i = this.projectDate.compareTo(project.projectDate);
    if(i != 0) return i;

    return this.projectName.compareTo(project.projectName);

}
Angelo van der Sijpt
  • 3,611
  • 18
  • 24
D.Blazer
  • 192
  • 1
  • 2
  • 12
  • So you need to sort based on date in descending order, and if dates are equal you need the Name sorting to be done on that subset? – aksappy Jun 27 '16 at 11:30
  • I think it's fine. Let's see what other people suggest. Apache Commons CompareToBuilder will also work. I have used that once. – Kartic Jun 27 '16 at 11:30

2 Answers2

7

Date#compareTo returns a value < 0 if this Date is before the Date argument and a value > 0 otherwise.

If you want to reverse the sort from new to old, you can just return the negative compare result:

@Override
public int compareTo(Project project) {
    int i = this.projectDate.compareTo(project.projectDate);
    if(i != 0) return -i;  // reverse sort

    return this.projectName.compareTo(project.projectName);
}
Modus Tollens
  • 5,083
  • 3
  • 38
  • 46
4

In Java 8, the Comparator interface has a method thenComparing. You can use this method to create a comparator that compare by more than one field.

If you have a comparator to compare alphabetically and other to compare by dates, you can combine the comparator to sort by the field you want:

Comparator<Project> nameComparator = ...
Comparator<Project> dateComparator = ...

You can mix the comparator, using the reverse comparator if needed. These are some examples:

Comparator<Project> nameAndDateComparator = nameComparator.thenComparing(dateComparator);
Comparator<Project> nameAndReversedDateComparator = nameComparator.thenComparing(dateComparator.reversed());

Then, you can use the method sort as usual with the comparator that matches your needs.

If you are not using Java 8, you can create an utility class to combine your comparators:

public class CombinedComparator<T> implements Comparator<T> {

    Comparator<T> firstComparator;
    Comparator<T> secondComparator;

    public CombinedComparator(Comparator<T> firstComparator, Comparator<T> secondComparator) {
        this.firstComparator = firstComparator;
        this.secondComparator = secondComparator;
    }

    @Override
    public int compare(T o1, T o2) {
        int result = firstComparator.compare(o1, o2);
        return (result != 0) ? result : secondComparator.compare(o1, o2);
    }

}

And you could create multiple fields comparators this way:

Comparator<Project> nameAndDateComparator = new CombinedComparator<Project>(nameComparator, dateComparator);

Comparator<Project> nameAndReversedDateComparator = new CombinedComparator<Project>(nameComparator, Collections.reverseOrder(dateComparator));
Lii
  • 11,553
  • 8
  • 64
  • 88
David SN
  • 3,389
  • 1
  • 17
  • 21