Re: Sorting vector Multiple Ways
Am 13.07.2013 23:35, schrieb Mike Copeland:
Is there a way to sort the vector below in more than one way?
Plenty.
The
code below works, but I find a need to sort and search on a second field
(eName). Is this possible? TIA
class MyEvents
{
public:
bool bIsScored;
int eSeq;
double eDist;
string evKey;
string eRoot;
string eEvent;
string eDate;
string eYear;
string eCode;
string eName;
bool operator<(MyEvents rhs) { return evKey < rhs.evKey; }
};
vector<MyEvents> evVect;
Old school (C++98) and fixed at compile-time:
struct by_eDist {
bool operator()(MyEvents const& a, MyEvents const& b) const {
return a.eDist < b.eDist;
}
};
std::sort(evVect.begin(),evVect.end(),by_eDist());
Boost-style (Boost.Phoenix) and fixed at compile-time:
std::sort(evVect.begin(),evVect.end(),
bind(&MyEvents::eDist,arg1) < bind(&MyEvents::eDist,arg2)
);
Using a C++11 lambda expression:
std::sort(begin(evVect),end(evVect),
[](MyEvents const& a, MyEvents const& b){
return a.eDist < b.eDist;
});
A little more "dynamic flexibility":
template<class Clazz, class MemberType>
struct by {
Clazz::*MemberType pmd;
by(Clazz::*MemberType pmd) : pmd(pmd) {}
bool operator()(MyEvents const& a, MyEvents const& b) const {
return (a.*pmd) < (b.*pmd);
}
};
std::sort(begin(evVect),end(evVect),
by<MyEvents,double>(&MyEvents::eDist) );
The types here are statically fixed but you can reuse the same functor
type for different members of the same type. So, if you use this and
offer all possibilities for members to sort by, only three different
sort functions will be instantiated by the compiler's template
mechanism: one for int, one for double and one for all the possible
string members. I'd prefer this to reduce code bloat. You can avoid even
more code bloat by using normal function pointers. But this will
probably a bit slower due to the indirection.
And just as a bonus: If you want to resolve ties according to a
different member, for example. 1st sort by eDist and when two elements
have the same eDist then sort by evKey, this is how you could do it in
C++11:
struct by_eDist_then_evKey {
bool operator()(MyEvents const& a, MyEvents const& b) const {
return std::tie(a.eDist,a.evKey) < std::tie(b.eDist,b.evKey);
}
};
std::tie creates a tuple of references. The standard library offers an
operator< for tuples which does a lexicographical comparison.
:-)
Cheers!
SG