Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sort objects in descending order when the < comparator is defined?

I have a class A and a < comparator. How can I use them to sort an array of A in descending order?

class A {
...
};

class LessA {
   bool operator()(const A& a1, const A& a2) const {
   ...
   }
}

vector<A> v;
sort(v.begin(), v.end(), ???);

I suppose I should replace the ??? with something based on LessA, but I can't figure out what should go in there. I thought of using a lambda function, but I was looking for something shorter.

like image 635
Paul Baltescu Avatar asked May 14 '13 18:05

Paul Baltescu


People also ask

How does Comparator sort descending?

In order to sort ArrayList in Descending order using Comparator, we need to use the Collections. reverseOrder() method which returns a comparator which gives the reverse of the natural ordering on a collection of objects that implement the Comparable interface.

Does Comparator sort ascending or descending?

The default sorting order for an object is ascending order like Integer will be sorted from low to high while descending order is just opposite. Collections. reverseOrder() returns a Comparator which will be used for sorting Objects in descending order.

How do you arrange items in descending order?

Descending order is an arrangement of numbers from the largest to the smallest. We start arranging the numbers by placing the largest number first and moving towards the smaller numbers one by one. For example, if we arrange the numbers 63, 99, 10, 87, 35 in descending order, we write them as 99, 87, 63, 35,10.


Video Answer


2 Answers

If you want to sort according to the relation defined by your LessA comparator, just pass an instance of LessA as the third argument (and, since you are using C++11, prefer the global std::begin() and std::end() functions):

std::sort(std::begin(a), std::end(a), LessA());
//                                    ^^^^^^^

Now if your LessA() expresses the < relation and you want to sort according to the opposite criterion, you could do:

std::sort(std::begin(a), std::end(a), 
    [] (A const& a1, A const& a2))
{
    return LessA()(a2, a1);
}

Another thing you could do is to let your custom comparator accept an argument that determines how it should perform the comparison:

class CompA {
    bool lessThan;
public:
    CompA(bool lessThan) : _lessThan(lessThan) { }
    bool operator()(const A& a1, const A& a2) const {
        if (_lessThan)
        {
            // return true iff a1 < a2;
        }
        else
        {
            // return true iff a1 > a2;
        }
    }
};

You could then use it this way to sort in ascending order:

std::sort(std::begin(a), std::end(a), CompA(true));

And this way to sort in descending order:

std::sort(std::begin(a), std::end(a), CompA(false));

Another possibility, given your original LessA comparator, is to use std::bind to swap the order of the arguments to your custom comparator:

LessA comp;
using namespace std::placeholders;
std::sort(std::begin(v), std::end(v), 
    std::bind(&LessA::operator(), comp, _2, _1));
like image 145
Andy Prowl Avatar answered Sep 19 '22 00:09

Andy Prowl


Sort the range backwards:

vector<A> v;
sort(v.rbegin(), v.rend(), LessA());

rbegin, and rend give you reverse iterators.

Encapsulate if it's too confusing:

void reverse_sort(vector<A>& v) {
    sort(v.rbegin(), v.rend(), LessA());    
}

Usage:

vector<A> v;
reverse_sort(v);
like image 30
Peter Wood Avatar answered Sep 22 '22 00:09

Peter Wood