10

Why does this:

#include <iostream>
#include <string>
#include <vector>                                                             
#include <algorithm>

using namespace std;

vector<pair<int, string>> list;

int main() {
    int one = 1, two = 2, three =3, five =5, six = 6;
    string bla = "bla";

    list.push_back( pair<int, string>(two, bla));
    list.push_back( pair<int, string>(one, bla));
    list.push_back( pair<int, string>(two, bla));
    list.push_back( pair<int, string>(six, bla));
    list.push_back( pair<int, string>(five, bla));

    sort(list.begin(), list.end());

    for(auto item : list) {
        cout << item.first << endl;
    }
}

work as intended? output is:

1
2
2
5
6

How std::sort gets how to sort my int-string pairs? How to make it do so for some class of mine as pair first? Is there a way to sort by second using std::sort?

DuckQueen
  • 772
  • 10
  • 62
  • 134
  • 2
    `std::pair` has a `operator<`. If you want `std::sort` to sort differently, give it a comparator. – chris May 22 '14 at 20:51
  • 2
    http://en.cppreference.com/w/cpp/utility/pair/operator_cmp – bolov May 22 '14 at 20:52
  • You may try providing a specialization for the `bool operator<(const& std::pair op1,const& std::pair op2)` function, and pass this for sorting. – πάντα ῥεῖ May 22 '14 at 20:53
  • 1
    Take a look at the accepted answer to this SO post - http://stackoverflow.com/questions/2819245/is-stdpairint-stdstring-ordering-well-defined – R Sahu May 22 '14 at 20:55
  • 1
    @MarkRansom He's got a `vector` named *list*. `std::sort` doesn't work with `std::list` since it requires RandomAccessIterators. – Praetorian May 22 '14 at 21:06
  • @Praetorian I thought `std::sort` would work in a degraded state with bidirectional iterators. I must be thinking of something else, perhaps `lower_bound`. – Mark Ransom May 22 '14 at 21:14

2 Answers2

12

Since operator< is defined for std::pair and it is based on std::pair::first and then std::pair::second (lexicographical), so your code is working as the standard. To sort it based on the second part of the std::pair you can try this:

std::sort(list.begin(), list.end(), [](const std::pair<int, string> &x,
                                       const std::pair<int, string> &y)
{
    return x.second < y.second;
});
masoud
  • 55,379
  • 16
  • 141
  • 208
6

There is one "obvious" ordering of product types induced by the respective orderings of the components, and that is lexicographical order:

(a, b) < (c, d)  <=>  a < c || (a == c && b < d)

This is the ordering used by operator< of std::pair. In your example, since all the first components are distinct, the ordering happens to be equal to the ordering of the first component. It gets more interesting if you have multiple occurences of the same value in the first component, in which the second component is used to break ties.

How to make it do so for some class of mine as pair first?

You just have to define operator< for your type. But keep in mind that the second component will be considered if necessary and you might not want that overhead.

Is there a way to sort by second using std::sort?

Yes, just use a custom comparator functor. You can always do that if you don't want to use the default operator< for sorting.

Niklas B.
  • 92,950
  • 18
  • 194
  • 224