I have a struct with members x,y,z and w. How do I sort efficiently first by x, then by y, by z and finally by w in C++?
If you want to implement a lexicographical ordering, then the simplest way is to use std::tie
to implement a less-than or greater-than comparison operator or functor, and then use std::sort
on a collection of your structs.
struct Foo
{
T x, y, z, w;
};
....
#include <tuple> // for std::tie
bool operator<(const Foo& lhs, const Foo& rhs)
{
// assumes there is a bool operator< for T
return std::tie(lhs.x, lhs.y, lhs.z, lhs.w) < std::tie(rhs.x, rhs.y, rhs.z, rhs.w);
}
....
#include <algorithm> // for std::sort
std::vector<Foo> v = ....;
std::sort(v.begin(), v.end());
If there is not a natural ordering for Foo
, it might be better to define comparison functors instead of implementing comparison operators. You can then pass these to sort:
bool cmp_1(const Foo& lhs, const Foo& rhs)
{
return std::tie(lhs.x, lhs.y, lhs.z, lhs.w) < std::tie(rhs.x, rhs.y, rhs.z, rhs.w);
}
std::sort(v.begin(), v.end(), cmp_1);
If you do not have C++11 tuple
support, you can implement this using std::tr1::tie
(use header <tr1/tuple>
) or using boost::tie
from the boost.tuple library.
You can turn a struct into a std::tuple
using std::tie
, and use the lexicographic comparison std::tuple::operator<
. Here's an example using a lambda to std::sort
#include <algorithm>
#include <tuple>
#include <vector>
struct S
{
// x, y, z, w can be 4 different types!
int x, y, z, w;
};
std::vector<S> v;
std::sort(std::begin(v), std::end(v), [](S const& L, S const& R) {
return std::tie(L.x, L.y, L.z, L.w) < std::tie(R.x, R.y, R.z, R.w);
});
This example supplies std:sort
with a comparison operator on-the-fly. If you always want to use lexicographic comparison, you could write a non-member bool operator<(S const&, S const&)
that would automatically be selected by std::sort
, or by ordered associative containers like std::set
and std::map
.
Regarding efficiency, from an online reference:
All comparison operators are short-circuited; they do not access tuple elements beyond what is necessary to determine the result of the comparison.
If you have a C++11 environment, prefer std::tie
over hand-written solutions given here. They are more error-prone and less readable.
This solution has at most 4 comparisons per element-compare and does not require construction of other objects:
// using function as comp
std::sort (quadrupleVec.begin(), quadrupleVec.end(), [](const Quadruple& a, const Quadruple& b)
{
if (a.x != b.x)
return a.x < b.x;
if (a.y != b.y)
return a.y < b.y;
if (a.z != b.z)
return a.z < b.z;
return a.w < b.w;
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With