tags:

views:

3300

answers:

5

If I have a vector of pairs

std::vector<std::pair<int, int> > vec;

is there and easy way to sort the list in increasing order based on the second element of the pair?

I know I can write a little function object that will do the work, but is there a way to use existing parts of the STL and std::less to do the work directly?

EDIT: I understand that I can write a separate function or class to pass to the third argument to sort. The question is whether or not I can build it out of standard stuff. I'd really something that looks like

std::sort(vec.begin(), vec.end(), std::something_magic<int, int, std::less>());
+1  A: 

Here is an example:
std::sort in a vector of pairs

Jason Lepack
A: 

You'd have to rely on a non standard select2nd

Greg Rogers
+11  A: 

Just use a custom comparator (it's an optional 3rd argument to std::sort)

struct sort_pred {
    bool operator()(const std::pair<int,int> &left, const std::pair<int,int> &right) {
        return left.second < right.second;
    }
};

std::sort(v.begin(), v.end(), sort_pred());

EDIT: in response to your edits to your question, here's some thoughts .... if you really wanna be creative and be able to reuse this concept a lot, just make a template:

template<class T1, class T2, class Pred = std::less<T> >
struct sort_pair_second {
    bool operator()(const std::pair<T1,T2>&left, const std::pair<T1,T2>&right) {
        Pred p;
        return p(left.second, right.second);
    }
};

then you can do this too:

std::sort(v.begin(), v.end(), sort_pair_second<int, int>());

or even

std::sort(v.begin(), v.end(), sort_pair_second<int, std::greater<int> >());

Though to be honest, this is all a bit overkilll, just write the 3 line function and be done with it :-P

Evan Teran
+10  A: 

You can use boost like this:

std::sort(a.begin(), a.end(), 
          boost::bind(&std::pair<int, int>::second, _1) <
          boost::bind(&std::pair<int, int>::second, _2));

I don't know a standard way to do this equally short and concise, but you can grab boost::bind it's all consisting of headers.

Johannes Schaub - litb
nicely done, you get an upvote for that :)
Evan Teran
thanks, i appreciate it :)
Johannes Schaub - litb
+1 for using Boost. Btw, with a modern compiler you could probably already replace boost with std::tr1 as this will be in the standard soon.
Andreas Magnusson
unfortunately, i tried the same with gcc trunk's c++1x std::bind, and it failed because it doesn't have the op< for bind. dunno however whether what c++1x says about this. probably it tells you to use lambda for that :)
Johannes Schaub - litb
I suppose boost isn't standard, but it's close enough. :-)
David Norman
+2  A: 

For something reusable:

template<template <typename> class P = std::less >
struct compare_pair_second {
    template<class T1, class T2> bool operator()(const std::pair<T1, T2>& left, const std::pair<T1, T2>& right) {
        return P<T2>()(left.second, right.second);
    }
};

You can use it as

std::sort(foo.begin(), foo.end(), compare_pair_second<>());

or

std::sort(foo.begin(), foo.end(), compare_pair_second<std::less>());
Leon Timmermans