1

I want to be able to sort the following vector - vector< pair< string , pair< int ,int > > > based on the 1st element of the pair< int , int> and if those are equal then sort them according to their second elements, how do I do that in C++ using STL's constructs?

This sort has to accomplish something on the lines of this

lets say E1 and E2 are 2 elements

if E1.second.first == E2.second.first then the comparison must be made with respect to the second elements.

AnkitSablok
  • 3,021
  • 7
  • 35
  • 52

3 Answers3

2

If you can't use C++11 features you can still do something like this:

typedef std::pair<std::string, std::pair<int, int>> AnkitSablok;

struct my_compare {
    bool operator()(const AnkitSablok &lhs, const AnkitSablok &rhs) const {
        return lhs.second < rhs.second;
    }
};

int main()
{
    std::vector<AnkitSablok> vec;

    std::sort(vec.begin(), vec.end(), my_compare());
}
Blastfurnace
  • 18,411
  • 56
  • 55
  • 70
  • it worked :D , thanks blastfurnace for such a great reply :D, grateful to you, in general can you explain me how to accomplish such jobs? some theory would be useful :) – AnkitSablok Nov 22 '13 at 22:21
  • 1
    [In C++03 local classes cannot be used as template arguments](http://stackoverflow.com/a/5751990/1762344). – Evgeny Panasyuk Nov 22 '13 at 22:22
  • @EvgenyPanasyuk: Thanks, it's been a while since I've used a strictly C++03 compiler. – Blastfurnace Nov 22 '13 at 22:24
  • Simple and neat! Just a suggestion, since you are anyways overloading `()`, why not overload `operator<`. No need of a functor and sort looks much neater `std::sort(vec.begin(), vec.end());` – theAlias Nov 22 '13 at 22:28
  • @AnkitSablok: `std::sort` takes an optional comparison function. This needs to be a callable object like a function pointer, function object, or lambda. I posted just one possible solution for your question. – Blastfurnace Nov 22 '13 at 22:30
  • @theAlias: This is just one possible solution. Overloading `operator<` would also work. – Blastfurnace Nov 22 '13 at 22:32
2

[...] based on the 1st element of the pair< int , int> and if those are equal then sort them according to their second elements [...]

std::pair already has lexicographical comparison C++03 20.2.2/6:

template <class T1, class T2>
bool operator<(const pair<T1, T2>& x, const pair<T1, T2>& y);

Returns: x.first < y.first || (!(y.first < x.first) && x.second < y.second)

So, as WhozCraig pointed out, you should just compare .seconds of outer pair.

This is a lambda expression, I dont have C++ 11 with me, is there no other way possible?

Use functor:

struct LessSecond
{
    template<typename T, typename U>
    bool operator()(const std::pair<T,U> &x, const std::pair<T,U> &y) const
    {
        return x.second < y.second;
    }
};
// ...
sort(x.begin(), x.end(), LessSecond());

Or maybe more generic version (depends on your needs):

struct LessSecondGeneric
{
    template<typename Pair>
    bool operator()(const Pair &x, const Pair &y) const
    {
        return x.second < y.second;
    }
};

LIVE DEMO:

#include <algorithm>
#include <iostream>
#include <iterator>
#include <utility>
#include <vector>

struct LessSecond
{
    template<typename T, typename U>
    bool operator()(const std::pair<T,U> &x, const std::pair<T,U> &y) const
    {
        return x.second < y.second;
    }
};

int main()
{
    using namespace std;

    vector<pair<string , pair<int, int>>> x
    {
        {"1", {2, 1}}, {"2", {1, 1}}, {"3", {1, 2}}
    };
    sort(x.begin(), x.end(), LessSecond());
    for(const auto &p : x)
        cout << p.first << " (" << p.second.first << ", " << p.second.second << ")" << endl;
}

Output is:

2 (1, 1)
3 (1, 2)
1 (2, 1)
Evgeny Panasyuk
  • 9,076
  • 1
  • 33
  • 54
  • Ok. thats gonna put the OP in a coma, but I like it none-the-less, particularly since it is generic. I'm dumping my answer. +1 – WhozCraig Nov 22 '13 at 22:23
0
sort(x.begin, x.end, [](const X & a, const X & b){return a.second.first < b.second.first ; }) ;

Where x is your container, and X is the type of an element.

woolstar
  • 5,063
  • 20
  • 31