Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there are a sort method that would take multiple comparators and use them in case the sort order is same for a list of elements?

I have a list of Offers to be given out. Each offer has a score, last date and offer value associated with it. I want these offers to be sorted on offer Score. This was simple to do using Collections.sort(..).

Now, if the offers have same score, i want to sort on last date. If the last dates is also same, I want to sort on Offer value.

I have written datesComparator and ValueComparator for this.

Then I did the following which is quite expensive

  1. Sort Offers based on offerScore.--> List

  2. Take out offers with same score from Step 1.--> List

  3. Sort Offers from Step 2 based on last Date and or Offer Value. --> List

  4. Add back List from Step 3 to List in Step 1.--> List

  5. For Step 4 , use sort on offer score again, since sort method doesn't change the order of offers with same score.

I was wondering if there's a simpler method that would take up multiple comparators and then the sort would take up next comparator in case the result of first comparator is same for consecutive offers!!

like image 266
the_way Avatar asked Mar 04 '23 13:03

the_way


2 Answers

You are looking for Comparator.thenComparing.

Returns a lexicographic-order comparator with another comparator. If this Comparator considers two elements equal, i.e. compare(a, b) == 0, other is used to determine the order.

default Comparator<T> thenComparing(Comparator<? super T> other) {
    Objects.requireNonNull(other);
    return (Comparator<T> & Serializable) (c1, c2) -> {
        int res = compare(c1, c2);
        return (res != 0) ? res : other.compare(c1, c2);
    };
}

For instance,

Comparator<Offer> comparator = 
    Comparator.comparingInt(Offer::getOfferScore)
              .thenComparing(Offer::getLastDate)
              .thenComparingInt(Offer::getOfferScore);

(assuming these methods exist)

UPDATE

Comparator<Offer> comparator =
// OfferScore -> DESC
Comparator.comparingInt(Offer::getOfferScore).reversed()
// Dates -> ASC
.thenComparing(Offer::getLastDate)                    
// Value -> DESC   
.thenComparing(Comparator.comparingInt(Offer::getOfferScore).reversed());
like image 66
Andrew Tobilko Avatar answered Apr 28 '23 19:04

Andrew Tobilko


The java.util.Comparator interface has all methods you need to chain comparisons together. So your code may look something like this:

        List<Offer> offers = getOffers();
        offers.sort(Comparator
                .comparing(Offer::getOfferScore)
                .thenComparing(Offer::getOfferValue)
                .thenComparing(Offer::getLastDate);
like image 32
Marc G. Smith Avatar answered Apr 28 '23 19:04

Marc G. Smith