STL sort question - c++

I have vector of structures:
vector<Custom> myvec;
Custom is a structure:
struct Custom
{
double key[3];
};
How to sort myvec by key[0]. key[1] or key[2] using STL sort algorithm?

Write a custom comparator:
template <int i> struct CustomComp
{
bool operator()( const Custom& lhs, const Custom& rhs) const
{
return lhs.key[i]<rhs.key[i];
}
};
and then sort e.g. by using std::sort(myvec.begin(),myvec.end(),CustomComp<0>()); (this sorts by the first key entry)
Or with a more recent compiler (with c++0x lambda support):
std::sort(myvec.begin(), myvec.end(),
[]( const Custom& lhs, const Custom& rhs) {return lhs.key[0] < rhs.key[0];}
);

By using a a custom comparator.
struct CustomLess {
size_t idx;
CustomLess(size_t i) : idx(i) {}
bool operator()(Custom const& a, Custom const& b) const {
return a.key[idx] < b.key[idx];
}
};
then
std::sort(myvec.begin(), myvec.end(), CustomLess(1)); // for 1
Note: I did not use a template because, while using a template enables the compiler to optimize for that specific index, it prevents you from selecting the index at runtime, e.g. based on userinput, so it's less flexible/can't do as much as the nontemplated version. And as we all know, premature optimization is evil :)

I'm not sure why so many of the answers posted are focusing on functors. There is no need for a functor with the OP's stated requirement. Here are 2 non-functor solutions:
1: Overload operator< in the Custom class
bool Custom::operator< (const Custom& rhs)
{
return key[0] < rhs.key[0];
}
// can call sort(myvec.begin(), myvec.end());
2: Create a custom comparison function
template<int i> bool CustomLess(const Custom& lhs, const Custom& rhs)
{
return lhs.key[i] < rhs.key[i];
}
// can call sort(myvec.begin(), myvec.end(), CustomLess<0>);

bool CompareCustoms(const Custom& lhs, const Custom& rhs)
{
// Compare criteria here
return (lhs.key[0] < rhs.key[0]);
}
sort(myvec.begin(), myvec.end(), CompareCustoms);

Related

Making a comparator from an ordered container

Given a list of objects, what is the cleanest way to create a functor object to act as a comparator, such that the comparator respects the ordering of the objects in the list. It is guaranteed that the objects in the list are unique, and the list contains the entire space of possible objects.
For example, suppose we have:
const std::vector<std::string> ordering {"dog", "cat", "mouse", "elephant"};
Now we want a function to act as a comparator, say for a map:
using Comparator = std::function<bool(const std::string&, const std::string&>;
using MyMap = std::map<std::string, int, Comparator>;
I have a solution, but it's not what I'd call pretty:
const auto cmp = [&ordering] (const auto& lhs, const auto& rhs)
{
const std::array<std::reference_wrapper<const std::decay_t<decltype(lhs)>, 2> values {lhs, rhs};
return *std::find_first_of(std::cbegin(ordering), std::cend(ordering),
std::cbegin(values), std::cend(values),
[] (const auto& lhs, const auto& rhs) {
return lhs == rhs.get();
}) == lhs;
};
Is there something a little less verbose?
You can use:
const std::vector<std::string> ordering {"dog", "cat", "mouse", "elephant"};
struct cmp
{
bool operator()(const std::string& lhs, const std::string& rhs)
{
return (std::find(ordering.begin(), ordering.end(), lhs) <
std::find(ordering.begin(), ordering.end(), rhs));
}
};
using MyMap = std::map<std::string, int, cmp>;
See it working at http://ideone.com/JzTNwt.
Just skip the algorithms and write a for-loop:
auto cmp = [&ordering](auto const& lhs, auto const& rhs) {
for (auto const& elem : ordering) {
// check rhs first in case the two are equal
if (elem == rhs) {
return false;
}
else if (elem == lhs) {
return true;
}
}
return false;
};
It might technically be longer than your solution, but I find it way easier to read.
Alternatively, depending on the size of the ordering, could throw both into a map:
std::unordered_map<std::string, int> as_map(std::vector<std::string> const& ordering)
{
std::unordered_map<std::string, int> m;
for (auto const& elem : ordering) {
m.emplace(elem, m.size());
}
return m;
}
auto cmp = [ordering_map = as_map(ordering)](auto const& lhs, auto const& rhs){
auto left = ordering_map.find(lhs);
auto right = ordering_map.find(rhs);
return left != ordering_map.end() && right != ordering_map.end() &&
left->second < right->second;
};
KISS. Build up your solution from reusable primitives with clear semantics.
order_by takes a projection A->B and returns an ordering on A using the ordering on B. It optionally takes an ordering on B (not used here):
template<class F, class Next=std::less<>>
auto order_by(F&& f, Next&& next = {}) {
return [f=std::forward<F>(f), next=std::forward<Next>(next)]
(auto&& lhs, auto&& rhs)->bool
{
return next(f(lhs), f(rhs));
};
}
index_in takes a container c and returns a function that takes an element, and determines its index in c:
template<class C>
auto index_in( C&& c ) {
return [c=std::forward<C>(c)](auto&& x){
using std::begin; using std::end;
return std::find( begin(c), end(c), x ) - begin(c);
};
}
template<class T>
auto index_in( std::initializer_list<T> il ) {
return [il](auto&& x){
using std::begin; using std::end;
return std::find( begin(il), end(il), x ) - begin(il);
};
}
We then compose them:
auto cmp = order_by( index_in(std::move(ordering) ) );
Each component can be independently tested and validated, and the composition "obviously" works. We can also rewrite index_in to use a faster lookup than linear, say a map from key to index, and we'd have two implementations that can unit test against each other.
I find order_by very often useful. index_in I've never had to use before.
This trick makes constructing the resulting map on one line, instead of storing cmp, practical, as the final description is short and clear.
template<class T>
using Comparator = std::function<bool(T const&, T const&>;
using MyMap = std::map<std::string, int, Comparator<std::string>>;
MyMap m = order_by( index_in({"dog", "cat", "mouse", "elephant"}) );
is also really pretty looking.
Here is a second approach.
We can move some of the work outside of the lambda.
template<class T0, class...Ts>
std::array< std::reference_wrapper<T0>, sizeof...(Ts)+1 >
make_ref_array( T0& t0, Ts&... ts ) {
return {std::ref(t0), std::ref(ts)...};
}
Then we can write the lambda from first principles instead of algorithms:
Comparator cmp = [&ordering] (const auto& lhs, const auto& rhs)
{
if (lhs==rhs) return false; // x is never less than x.
for (auto&& e:ordering)
for (auto&& z:make_ref_array(lhs, rhs))
if (e==z.get())
return std::addressof(z.get())==std::addressof(lhs);
return false;
};
The resulting lambda is a bit less verbose.
If you had ranged based algorithms it might also help.
In both my solutions, all elements not in the list are greater than any element in the list, and are equal to each other.
I suggest you make the key a structure type containing the key (std::string in this case) and the index in the array.
Something like
struct Key
{
std::string str;
size_t index;
};
using MyMap = std::map<Key, int, Comparator>;
struct Comparator
{
bool operator()(const Key &a, const Key &b) const
{
return a.index < b.index;
}
};
This is basically the same as R. Sahu's answer. But since I'd already typed it up... The primary thing I'm advocating here is keeping ordering internal to cmp, presuming that you don't need it externally.
const auto cmp = [ordering = vector<string>{ "dog", "cat", "mouse", "elephant" }](const auto& lhs, const auto& rhs) { return find(cbegin(ordering), cend(ordering), lhs) < find(cbegin(ordering), cend(ordering), rhs); };
Live Example
Encapsulating the ordering within cmp makes the scope that a reader has to look at when he changes ordering much smaller. (Personally I wouldn't construct cmp as an Rvalue, I'd just dump it directly into the constructor for the same reason... Though it is becoming a bit of a redonculous one-liner:
map<string, int, function<bool(const string&, const string&)>> myMap([ordering = vector<string>{ "dog", "cat", "mouse", "elephant" }](const auto& lhs, const auto& rhs) { return find(cbegin(ordering), cend(ordering), lhs) < find(cbegin(ordering), cend(ordering), rhs); });
Live Example

Construction a vector from the concatenation of 2 vectors

Is there a way to construct a vector as the concatenation of 2 vectors (Other than creating a helper function?)
For example:
const vector<int> first = {13};
const vector<int> second = {42};
const vector<int> concatenation = first + second;
I know that vector doesn't have an addition operator like string, but that's the behavior that I want. Such that concatenation would contain: 13 and 42.
I know that I can initialize concatenation like this, but it prevents me from making concatenation const:
vector<int> concatenation = first;
first.insert(concatenation.end(), second.cbegin(), second.cend());
No, it's not possible if you require that
no helper function is defined, and
the resulting vector can be declared const.
template<typename T>
std::vector<T> operator+(const std::vector<T>& v1, const std::vector<T>& v2){
std::vector<T> vr(std::begin(v1), std::end(v1));
vr.insert(std::end(vr), std::begin(v2), std::end(v2));
return vr;
}
This does require a helper "function", but at least it allows you to use it as
const vector<int> concatenation = first + second;
I think you have to write a help function. I'd write it as:
std::vector<int> concatenate(const std::vector<int>& lhs, const std::vector<int>& rhs)
{
auto result = lhs;
std::copy( rhs.begin(), rhs.end(), std::back_inserter(result) );
return result;
}
The call it as:
const auto concatenation = concatenate(first, second);
If the vectors are likely to be very large (or contain elements that are expensive to copy), then you might need to do a reserve first to save reallocations:
std::vector<int> concatenate(const std::vector<int>& lhs, const std::vector<int>& rhs)
{
std::vector<int> result;
result.reserve( lhs.size() + rhs.size() );
std::copy( lhs.begin(), lhs.end(), std::back_inserter(result) );
std::copy( rhs.begin(), rhs.end(), std::back_inserter(result) );
return result;
}
(Personally, I would only bother if there was evidence it was a bottleneck).
class Vector : public vector<int>
{
public:
Vector operator+(const Vector& vec);
};
Vector Vector::operator+(const Vector& vec)
{
for (int i = 0; i < vec.size(); i++)
{
this->push_back(vec[i]);
}
return *this;
}
Let me preface this by saying this is a hack, and will not give an answer to how to do this using a vector. Instead we'll depend on sizeof(int) == sizeof(char32_t) and use a u32string to contain our data.
This answer makes it exceedingly clear that only primitives can be used in a basic_string, and that any primitive larger than 32-bits would require writing a custom char_traits, but for an int we can just use u32string.
The qualification for this can be validated by doing:
static_assert(sizeof(int) == sizeof(char32_t));
Once size equality has been established, and with the knowledge that things like non-const data, and emplace or emplace_back cannot be used, u32string can be used like a vector<int>, with the notable inclusion of an addition opperator:
const vector<int> first = {13};
const vector<int> second = {42};
const u32string concatenation = u32string(first.cbegin(), first.cend()) + u32string(second.cbegin(), second.cend());
[Live Example]
I came across this question looking for the same thing, and hoping there was an easier way than the one I came up with... seems like there isn't.
So, some iterator trickery should do it if you don't mind a helper template class:
#include <vector>
#include <iostream>
template<class T>
class concat
{
public:
using value_type = typename std::vector<T>::const_iterator::value_type;
using difference_type = typename std::vector<T>::const_iterator::difference_type;
using reference = typename std::vector<T>::const_iterator::reference;
using pointer = typename std::vector<T>::const_iterator::pointer;
using iterator_category = std::forward_iterator_tag;
concat(
const std::vector<T>& first,
const std::vector<T>& last,
const typename std::vector<T>::const_iterator& iterator) :
mFirst{first},
mLast{last},
mIterator{iterator}{}
bool operator!= ( const concat& i ) const
{
return mIterator != i.mIterator;
}
concat& operator++()
{
++mIterator;
if(mIterator==mFirst.end())
{
mIterator = mLast.begin();
}
return *this;
}
reference operator*() const
{
return *mIterator;
}
private:
const std::vector<T>& mFirst;
const std::vector<T>& mLast;
typename std::vector<T>::const_iterator mIterator;
};
int main()
{
const std::vector<int> first{0,1,2,3,4};
const std::vector<int> last{5,6,7,8,9};
const std::vector<int> concatenated(
concat<int>(first,last,first.begin()),
concat<int>(first,last,last.end()));
for(auto i: concatenated)
{
std::cout << i << std::endl;
}
return 0;
}
You may have to implement operator++(int) or operator== depending on how your STL implements the InputIterator constructor, this is the minimal iterator code example I could come up with for MingW GCC.
Have Fun! :)

How to use lambda auto parameters in C++11

I have a code in C++14. However, when I used it in C++11, it has an error at const auto. How to use it in C++11?
vector<vector <int> > P;
std::vector<double> f;
vector< pair<double, vector<int> > > X;
for (int i=0;i<N;i++)
X.push_back(make_pair(f[i],P[i]));
////Sorting fitness descending order
stable_sort(X.rbegin(), X.rend());
std::stable_sort(X.rbegin(), X.rend(),
[](const auto&lhs, const auto& rhs) { return lhs.first < rhs.first; });
C++11 doesn't support generic lambdas. That's what auto in the lambda's parameter list actually stands for: a generic parameter, comparable to parameters in a function template. (Note that the const isn't the problem here.)
Note: C++14 does support lambdas with auto, const auto, etc. You can read about it here.
You have basically two options:
Type out the correct type instead of auto. Here it is the element type of X, which is pair<double, vector<int>>. If you find this unreadable, a typedef can help.
std::stable_sort(X.rbegin(), X.rend(),
[](const pair<double, vector<int>> & lhs,
const pair<double, vector<int>> & rhs)
{ return lhs.first < rhs.first; });
Replace the lambda with a functor which has a call operator template. That's how generic lambdas are basically implemented behind the scene. The lambda is very generic, so consider putting it in some global utility header. (However do not using namespace std; but type out std:: in case you put it in a header.)
struct CompareFirst {
template <class Fst, class Snd>
bool operator()(const pair<Fst,Snd>& l, const pair<Fst,Snd>& r) const {
return l.first < r.first;
}
};
std::stable_sort(X.rbegin(), X.rend(), CompareFirst());
I know there is an accepted answer, but you can also use decltype in C++11 for this, it looks a bit messy...
stable_sort(X.rbegin(), X.rend(), [](decltype(*X.cbegin()) lhs, decltype(lhs) rhs) { return lhs.first < rhs.first; });
Use cbegin() here as you get the const correct value_type of the container.
Unfortunately, generic lambdas that take auto (whether const or not) is a C++14 only feature.
See here https://isocpp.org/wiki/faq/cpp14-language#generic-lambdas for some more details.
Alternatively you can directly use the value_type typedef of the container with a decltype, like
std::stable_sort(X.rbegin(), X.rend(),
[](const decltype(X)::value_type & lhs,
const decltype(X)::value_type & rhs)
{return lhs.first < rhs.first; }
);
const auto is not supported in C++11 as a lambda parameter (actually generic lambdas are not supported in C++11).
To fix:
using pair_type = std::pair<double, std::vector<int>>;
vector<pair_type> X;
std::stable_sort(X.rbegin(), X.rend(),
[](const pair_type&lhs, const pair_type& rhs)
{ return lhs.first < rhs.first; });

Overload make_heap?

I have a std::vector<t_Mont> v, t_Mont have {float val, int i and int j}
I want to do make_heap(v.begin(), v.end()) and pop_head(v.begin(), v.end()) but I get a lot of errors on console. I think this is because I'm passing a vector of type t_mont.
I want to make_heap on the value of the variable val of v.
What I have to do to compile me? I have to overload make_heap and pop_head? How I do it?
Thanks.
My code:
std::vector<t_Mont> v;
for (int i = 0; i < nCellsHeight; i++) {
for (int j = 0; j < nCellsWidth; j++) {
t_Mont aux;
aux.i = i;
aux.j = j;
aux.val = cellValues[i][j];
v.push_back(aux);
}
}
std::make_heap(v.begin(), v.end());
while (v.begin() != v.end()) {
std::cout << "Best of v = " << v[0].val << std::endl;
std::pop_heap(v.begin(), v.end());
v.pop_back();
std::make_heap(v.begin(), v.end());
}
make_heap and related functions will, by default, compare values using <. You need to either provide an overload of that operator for your type:
bool operator<(t_Mont const & lhs, t_Mont const & rhs) {
return lhs.val < rhs.val;
}
or provide a custom comparator when you call the functions:
auto comp = [](t_Mont const & lhs, t_Mont const & rhs){return lhs.val < rhs.val;};
std::make_heap(v.begin(), v.end(), comp);
If you're stuck with an ancient pre-lambda compiler, define a function type in full:
struct Comp {
bool operator()(t_Mont const & lhs, t_Mont const & rhs){return lhs.val < rhs.val;}
};
std::make_heap(v.begin(), v.end(), Comp());
t_Mont has to be comparable with operator< for this to work, or you have to use the other form of std::make_heap and pass a comparison functor alongside the iterators (if, for some reason, you don't want t_Mont to be generally sortable).
That is to say, you have to define
bool operator<(t_Mont const &lhs, t_Mont &rhs) {
// return true if lhs is less than rhs, false otherwise.
}
so that you get a total order (i.e., a < b means !(b < a), a < b and b < c mean a < c, and !(a < a)), or
struct t_Mont_compare {
bool operator()(t_Mont const &lhs, t_Mont &rhs) const{
// return true if lhs is less than rhs, false otherwise.
}
}
with the same conditions.
You have to define a function object for making comparisons between two t_Monts. The declaration of make_heap looks like this :
template <class RandomAccessIterator, class Compare>
void make_heap (RandomAccessIterator first, RandomAccessIterator last, Compare comp );
Or just create a function like this :
bool comp_tmonts(const t_Mont& a, const t_Mont& b)
{
/* Insert your comparison criteria for less than here.
Return a boolean value corresponding to whether a is less than b */
}
Then pass this to your make_heap function as the third argument :
make_heap(v1.begin(), v1.end(), comp_tmonts);

Chaining of ordering predicates (e.g. for std::sort)

You can pass a function pointer, function object (or boost lambda) to std::sort to define a strict weak ordering of the elements of the container you want sorted.
However, sometimes (enough that I've hit this several times), you want to be able to chain "primitive" comparisons.
A trivial example would be if you were sorting a collection of objects that represent contact data. Sometimes you will want to sort by last name, first name, area code. Other times first name, last name - yet other times age, first name, area code... etc
Now, you can certainly write an additional function object for each case, but that violates the DRY principle - especially if each comparison is less trivial.
It seems like you should be able to write a hierarchy of comparison functions - the low level ones do the single, primitive, comparisons (e.g. first name < first name), then higher level ones call the lower level ones in succession (probably chaining with && to make use of short circuit evaluation) to generate the composite functions.
The trouble with this approach is that std::sort takes a binary predicate - the predicate can only return a bool. So if you're composing them you can't tell if a "false" indicates equality or greater than. You can make your lower level predicates return an int, with three states - but then you would have to wrap those in higher level predicates before they could be used with std::sort on their own.
In all, these are not insurmountable problems. It just seems harder than it should be - and certainly invites a helper library implementation.
Therefore, does anyone know of any pre-existing library (esp. if it's a std or boost library) that can help here - of have any other thoughts on the matter?
[Update]
As mentioned in some of the comments - I've gone ahead and written my own implementation of a class to manage this. It's fairly minimal, and probably has some issues with it in general. but on that basis, for anyone interested, the class is here:
http://pastebin.com/f52a85e4f
And some helper functions (to avoid the need to specify template args) is here:
http://pastebin.com/fa03d66e
You could build a little chaining system like so:
struct Type {
string first, last;
int age;
};
struct CmpFirst {
bool operator () (const Type& lhs, const Type& rhs) { return lhs.first < rhs.first; }
};
struct CmpLast {
bool operator () (const Type& lhs, const Type& rhs) { return lhs.last < rhs.last; }
};
struct CmpAge {
bool operator () (const Type& lhs, const Type& rhs) { return lhs.age < rhs.age; }
};
template <typename First, typename Second>
struct Chain {
Chain(const First& f_, const Second& s_): f(f_), s(s_) {}
bool operator () (const Type& lhs, const Type& rhs) {
if(f(lhs, rhs))
return true;
if(f(rhs, lhs))
return false;
return s(lhs, rhs);
}
template <typename Next>
Chain <Chain, Next> chain(const Next& next) const {
return Chain <Chain, Next> (*this, next);
}
First f;
Second s;
};
struct False { bool operator() (const Type& lhs, const Type& rhs) { return false; } };
template <typename Op>
Chain <False, Op> make_chain(const Op& op) { return Chain <False, Op> (False(), op); }
Then to use it:
vector <Type> v; // fill this baby up
sort(v.begin(), v.end(), make_chain(CmpLast()).chain(CmpFirst()).chain(CmpAge()));
The last line is a little verbose, but I think it's clear what's intended.
One conventional way to handle this is to sort in multiple passes and use a stable sort. Notice that std::sort is generally not stable. However, there’s std::stable_sort.
That said, I would write a wrapper around functors that return a tristate (representing less, equals, greater).
You can try this:
Usage:
struct Citizen {
std::wstring iFirstName;
std::wstring iLastName;
};
ChainComparer<Citizen> cmp;
cmp.Chain<std::less>( boost::bind( &Citizen::iLastName, _1 ) );
cmp.Chain<std::less>( boost::bind( &Citizen::iFirstName, _1 ) );
std::vector<Citizen> vec;
std::sort( vec.begin(), vec.end(), cmp );
Implementation:
template <typename T>
class ChainComparer {
public:
typedef boost::function<bool(const T&, const T&)> TComparator;
typedef TComparator EqualComparator;
typedef TComparator CustomComparator;
template <template <typename> class TComparer, typename TValueGetter>
void Chain( const TValueGetter& getter ) {
iComparers.push_back( std::make_pair(
boost::bind( getter, _1 ) == boost::bind( getter, _2 ),
boost::bind( TComparer<TValueGetter::result_type>(), boost::bind( getter, _1 ), boost::bind( getter, _2 ) )
) );
}
bool operator()( const T& lhs, const T& rhs ) {
BOOST_FOREACH( const auto& comparer, iComparers ) {
if( !comparer.first( lhs, rhs ) ) {
return comparer.second( lhs, rhs );
}
}
return false;
}
private:
std::vector<std::pair<EqualComparator, CustomComparator>> iComparers;
};
std::sort is not guaranteed to be stable because stable sorts are usually slower than non-stable ones ... so using a stable sort multiple times looks like a recipe for performance trouble...
And yes it's really a shame that sort ask for a predicate:
I see no other way than create a functor accepting a vector of tristate functions ...
The chaining solution is verbose. You could also use boost::bind in conjunction with std::logical_and to build your sorting predicate. See the linked article for more information: How the boost bind library can improve your C++ programs
Variadic templates in C++ 11 give a shorter option:
#include <iostream>
using namespace std;
struct vec { int x,y,z; };
struct CmpX {
bool operator() (const vec& lhs, const vec& rhs) const
{ return lhs.x < rhs.x; }
};
struct CmpY {
bool operator() (const vec& lhs, const vec& rhs) const
{ return lhs.y < rhs.y; }
};
struct CmpZ {
bool operator() (const vec& lhs, const vec& rhs) const
{ return lhs.z < rhs.z; }
};
template <typename T>
bool chained(const T &, const T &) {
return false;
}
template <typename CMP, typename T, typename ...P>
bool chained(const T &t1, const T &t2, const CMP &c, P...p) {
if (c(t1,t2)) { return true; }
if (c(t2,t1)) { return false; }
else { return chained(t1, t2, p...); }
}
int main(int argc, char **argv) {
vec x = { 1,2,3 }, y = { 2,2,3 }, z = { 1,3,3 };
cout << chained(x,x,CmpX(),CmpY(),CmpZ()) << endl;
return 0;
}