ペアの2番目の要素に基づいてペアのベクトルをソートするにはどうすればよいですか?


133

ペアのベクトルがある場合:

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

ペアの2番目の要素に基づいてリストを昇順でソートする簡単な方法はありますか?

私は仕事を行います小さな関数オブジェクトを書くことができます知っているが、既存の部品を使用する方法があるSTLをし、std::less直接作業を行うには?

編集:私は、ソートするために3番目の引数に渡す別の関数またはクラスを作成できることを理解しています。問題は、標準的なものから構築できるかどうかです。私は本当に次のようになります:

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

次に例を示します。<br> std :: sortのペアのベクトル
LeppyR64

1
C ++にはラムダがないため、希望どおりに実行することはできません。別の関数/ファンクタを作成する必要があります。これはワンライナーになる可能性があるため、大したことはないはずです。
エヴァンテラン

1
C ++にラムダが追加されました!ウー!
デビッドプール

回答:


212

編集:c ++ 14を使用すると、型のパラメーターを持つことができるラムダのおかげで、最善の解決策は非常に簡単に記述できますautoこれが私のお気に入りのソリューションです

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

カスタムコンパレーターを使用するだけです(これはのオプションの3番目の引数です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());

C ++ 11コンパイラを使用している場合は、ラムダを使用して同じように記述できます。

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

編集:質問への編集に応じて、ここにいくつかの考えがあります... 本当に創造的になり、このコンセプトをたくさん再利用したい場合は、テンプレートを作成してください:

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

その後、あなたもこれを行うことができます:

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

あるいは

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

正直なところ、これは少しやり過ぎです。3行の関数を記述して、それで完了してください:-P


これは異なっていることに注意してくださいoperator<の中でpair<T1,T2>。デフォルトのコンパレータは最初と2番目の要素の両方を使用します(最初の要素が等しい場合)。ここでは2番目のものだけが使用されています。
Googol 2014

@Googol:OPはを求め、正確にどのような...彼は言ったのです: "is there and easy way to sort the list in increasing order based on the second element of the pair?"
エヴァン・テラン

@ evan-teran、はい、知っています。両方の秒の要素が等しい場合、結果が混乱する可能性があることを示しただけです(たとえば、並べ替えに使用した場合)。この問題は、タイブレークに2番目の要素を使用するため、デフォルトのコンパレータの影響を受けません。2つ目の要素を比較の主要情報として使用するコンパレータを探してこの質問に到達しましたが、最初の要素をタイブレイクに使用することも必要だったので、他の人がその点を見逃さないようにしたい実際、そうしました)。
Googol 2014

71

あなたはこのようにブーストを使うことができます:

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

これを同じように短くて簡潔にする標準的な方法はわかりませんが、boost::bindすべてヘッダーで構成されていることを理解できます。


1
ブーストを使用するための+1。ところで、最近のコンパイラでは、ブーストをstd :: tr1に置き換えることができます。これは、まもなく標準になる予定です。
Andreas Magnusson

残念ながら、gccトランクのc ++ 1x std :: bindで同じことを試しましたが、バインド用のop <がないため失敗しました。しかし、c ++ 1xがこれについて何を言っているのかはわかりません。おそらくそれはラムダを使用するように指示します:)
Johannes Schaub-litb 2008

1
ブーストは標準ではないと思いますが、十分に近いです。:-)
デビッドノーマン

この回答に対するフォローアップの質問をここに投稿しました:stackoverflow.com/q/4184917/220636
nabulke 2010年

34

アルゴリズムのソート関数を使用して独自の比較関数を追加するのはかなり簡単です

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

次に、2番目の選択に基づいて比較を行う必要があるため、「myComparison」を次のように宣言します。

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

5
シンプルで「要点」。ブーストや特定のC ++バージョンは必要ありません。+1
Thomio 2016年

1
これは最適なソリューションとしてマークする必要があります。それを実装するのにc ++ 14は必要ありません。
Kartik Chauhan 2017

この比較がどのように機能するかを説明してもらえますか?一度に2つの要素をmyComparisionに渡していますか?また、a.second <b.secondはどのような役割を果たしますか?
時代標準

30

C ++ 0xでは、ラムダ関数を使用できます。

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

この例では、戻り値の型boolは暗黙的に推定されています。

ラムダの戻り値の型

ラムダ関数に単一のステートメントがあり、これがreturnステートメントである場合、コンパイラーは戻りの型を推定できます。C ++ 11から、§5.1.2/ 4:

...

  • 複合ステートメントの形式が{ return expression ; }、左辺値から右辺値への変換(4.1)、配列からポインターへの変換(4.2)、および関数からポインターへの変換(4.3)の後に返される式のタイプである場合。
  • それ以外の場合void

戻り値の型を明示的に指定するには[]() -> Type { }、次のような形式を使用します。

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

1
なんでif (lhs.second == 0)
ブタ

特に意味はありません。 またはlhs.second < rhs.secondが返されるtrue場合がfalseあり、コンパイラーはを明確に推定できboolます。[]() -> Type { }ケースを説明したかっただけです。
Andreas Spindler

少なくともclangでは、この暗黙の推定は正しく機能しない可能性があります。ラムダの戻り値の型として-> boolを追加して、正しく機能させる必要がありました。
MoDJ 2018

5

再利用可能なもの:

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

次のように使用できます

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

または

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


-1

std::sort()通常どおりに使用できるように、ペアの要素を交換してみてください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.