Reputation: 2809
I have the following vector
with pair values:
first 3 second 2
first 1 second 2
first 1 second 1
first 2 second 2
I would like to sort my vector such that the result would be
==========================
first 1 second 2
first 1 second 1
first 2 second 2
first 3 second 2
That means:
My code looks like:
#include <utility> // std::pair
#include <iostream> // std::cout
#include <vector>
typedef std::pair<double, double> my_pair;
struct sort_pred
{
bool operator () (const my_pair& left, const my_pair& right)
{
return (left.first < right.first) && (left.second > right.second);
}
};
int main () {
std::vector<my_pair> data;
data.push_back(my_pair(3,2) );
data.push_back(my_pair(1,2) );
data.push_back(my_pair(1,1) );
data.push_back(my_pair(2,2) );
for(auto a: data)
std::cout << "first "<< a.first << " second " << a.second << std::endl;
std::cout << "==========================\n";
std::sort(data.begin(), data.end(), sort_pred());
for(auto a: data)
std::cout << "first "<< a.first << " second " << a.second << std::endl;
return 0;
}
The condition in the sort_pred
expressed what I would like to do, but is not correct. I get wrong values.
Any idea how this can be easily solved?
Upvotes: 1
Views: 2801
Reputation: 16156
You want A to be before B if
In code that is
(a.first < b.first) or
((a.first == b.first) and
(b.second < a.second))
But this is suboptimal, from a programming point of view: Now you need an additional operator==
implemented.
But since a value can only be less, equal or greater than another, you can rewrite that to
(a.first < b.first) or
(not (b.first > a.first) and
(b.second < a.second))
Upvotes: 0
Reputation: 310990
Here you are
#include <iostream>
#include <vector>
#include <algorithm>
#include <utility>
typedef std::pair<double, double> my_pair;
struct sort_pred
{
bool operator ()( const my_pair &left, const my_pair &right ) const
{
return ( left.first < right.first ) ||
( !( right.first < left.first ) && ( right.second < left.second ) );
}
};
int main()
{
std::vector<my_pair> data;
data.push_back( my_pair( 3, 2 ) );
data.push_back( my_pair( 1, 2 ) );
data.push_back( my_pair( 1, 1 ) );
data.push_back( my_pair( 2, 2 ) );
std::stable_sort( data.begin(), data.end(), sort_pred() );
for ( const auto &p : data ) std::cout << p.first << ' ' << p.second << std::endl;
}
The program output is
1 2
1 1
2 2
3 2
Upvotes: 0
Reputation: 75
I think your predicate is wrong ?
If I understand correctly, you want precedence on the first element, and only in case of equality on the second element?
so maybe something like:
struct sort_pred
{
bool operator () (const my_pair& left, const my_pair& right)
{
return (left.first == right.first) ?
(left.second > right.second) :
(left.first < right.first);
}
};
Upvotes: 0
Reputation: 303087
Your comparator isn't quite right, since you want it to return true
if either the first check succeeds OR the first are equal and the second check succeeds. You only want to check the second
s if the first
s are equal. So something like this:
struct sort_pred
{
bool operator()(const my_pair& left, const my_pair& right) const
{
if (left.first != right.first) {
return left.first < right.first;
}
return left.second > right.second;
}
};
This can be simplified using the fact that tuple
s are lexicographically comparable:
struct sort_pred
{
bool operator()(const my_pair& left, const my_pair& right) const
{
return std::tie(left.first, right.second) <
std::tie(right.first, left.second);
}
};
Upvotes: 7
Reputation: 41106
You have to distinguish more cases:
bool operator () (const my_pair& left, const my_pair& right)
{
if (left.first < right.first)
return true;
if (left.first != right.first)
return false;
// when primary criterion is equal:
if (left.second > right.second)
// you want this to sort descending, right?
return true;
// .... other criteria
return false;
}
Upvotes: 0
Reputation: 10064
Your use of && doesn't really make sense. It goes on to evaluate the second element if left.first > right.first
, but really you want that to only happen if left.first == right.first
.
This should work:
bool operator () (const my_pair& left, const my_pair& right)
{
if (left.first != right.first)
return left.first < right.first;
else
return left.second > right.second;
}
Upvotes: 0
Reputation: 65620
This is possible with a bit of tweaking to your predicate:
struct sort_pred
{
bool operator () (const my_pair& lhs, const my_pair& rhs)
{
return lhs.first<rhs.first ||
(!(rhs.first<lhs.first) && lhs.second>rhs.second);
}
};
Upvotes: 0