web-dev-qa-db-fra.com

Comment trier un vecteur de paires basé sur le deuxième élément de la paire?

Si j'ai un vecteur de paires:

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

Existe-t-il un moyen simple de trier la liste par ordre croissant en fonction du deuxième élément de la paire?

Je sais que je peux écrire un petit objet de fonction qui fera le travail, mais existe-t-il un moyen d'utiliser des parties existantes du STL et std::less faire le travail directement?

EDIT: Je comprends que je peux écrire une fonction ou une classe séparée à passer au troisième argument à trier. La question est de savoir si je peux le construire à partir de matériel standard. Je voudrais vraiment quelque chose qui ressemble à:

std::sort(vec.begin(), vec.end(), std::something_magic<int, int, std::less>());
120
David Norman

EDIT : en utilisant c ++ 14, la meilleure solution est très facile à écrire grâce aux lambdas qui peuvent maintenant avoir des paramètres de type auto. Ceci est ma solution préférée actuelle

std::sort(v.begin(), v.end(), [](auto &left, auto &right) {
    return left.second < right.second;
});

Utilisez simplement un comparateur personnalisé (c'est un 3ème argument optionnel pour 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());

Si vous utilisez un compilateur C++ 11, vous pouvez écrire la même chose avec lambdas:

std::sort(v.begin(), v.end(), [](const std::pair<int,int> &left, const std::pair<int,int> &right) {
    return left.second < right.second;
});

EDIT : en réponse aux modifications que vous avez apportées à votre question, voici quelques réflexions ... si vous vraiment voulez être créatif et pouvoir pour réutiliser beaucoup ce concept, créez un modèle:

template <class T1, class T2, class Pred = std::less<T2> >
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);
    }
};

alors vous pouvez le faire aussi:

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

ou même

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

Pour être honnête, c’est un peu exagéré. Il suffit d’écrire la fonction 3 lignes et d’en finir avec :-P

188
Evan Teran

Vous pouvez utiliser boost comme ceci:

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

Je ne connais pas un moyen standard de le faire aussi court et concis, mais vous pouvez saisir boost::bind tout est constitué d'en-têtes.

70

Avec C++ 0x, nous pouvons utiliser les fonctions lambda:

using namespace std;
vector<pair<int, int>> v;
        .
        .
sort(v.begin(), v.end(),
     [](const pair<int, int>& lhs, const pair<int, int>& rhs) {
             return lhs.second < rhs.second; } );

Dans cet exemple, le type de retour bool est implicitement déduit.

types de retour Lambda

Lorsqu'une fonction lambda a une seule instruction, et qu'il s'agit d'une instruction return, le compilateur peut en déduire le type de retour. À partir de C++ 11, §5.1.2/4:

...

  • Si l'instruction composée est de la forme { return expression ; }, Le type de l'expression renvoyée après la conversion de lvalue en valeur (4.1), la conversion de tableau en pointeur (4.2) et la conversion de fonction en pointeur ( 4,3);
  • sinon, void.

Pour spécifier explicitement le type de retour, utilisez la forme []() -> Type { }, comme dans:

sort(v.begin(), v.end(),
     [](const pair<int, int>& lhs, const pair<int, int>& rhs) -> bool {
             if (lhs.second == 0)
                 return true;
             return lhs.second < rhs.second; } );
30
Andreas Spindler

C'est assez simple, vous utilisez la fonction de tri de l'algorithme et ajoutez votre propre fonction de comparaison

vector< pair<int,int > > v;
sort(v.begin(),v.end(),myComparison);

Maintenant, vous devez faire la comparaison sur la deuxième sélection, alors déclarez-vous "myComparison" comme

bool myComparison(const pair<int,int> &a,const pair<int,int> &b)
{
       return a.second<b.second;
}
29
Ezio

Pour quelque chose de réutilisable:

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);
    }
};

Vous pouvez l'utiliser comme

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

ou

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

Vous devrez vous appuyer sur un non standard select2nd

1
Greg Rogers