なんとな~くしあわせ?の日記

JavaとかAWSの設定とかをメモする技術ブログ

vector<クラス>をソートしたいとき

vector内部にオリジナルのクラスを作って、なおかつソートさせたいときがありますよね。
そんな時はbinary predicateをstd::sortの3つ目の引数に設定してやればいいらしい。

「binary predicate」は日本語でなんて言えばいいんだろう?逐語訳すると二進述語かな。意味的には2択の条件を確定させる述語ぐらいか。あと「functor」も訳語ないのかな?「演算子多重定義関数オブジェクト」?wikipediaに記事があった 関数オブジェクト - Wikipedia

2015/11/22
この記事に誰も突っ込んでくれなかったことが非常に悲しいのだが、訂正
「binary predicate」は単純に「述語」、「functor」は「関手」と訳すのが適当と思われる。関数型言語的機能なのだ。

2017/04/07
この記事に誰も突っ込んでくれなかったことが非常に悲しいのだが、
std::binary_functionはC++11から非推奨になっている。とりあえず、lambda式などを使ってソートしてはいかがだろうか。
c++ - why unary_function,binary_function is removed from c++11? - Stack Overflow

参考:STL Sorting: How to sort a 'std::vector' containing classes/structures?
「Re: STL Sorting: How to sort a 'std::vector' containing classes/structures?」の人のソースコードをコピーしています。

どうやらこの人は二種類のやり方を同時に試しているようです
① std::sortの引数にpredicateを追加するやり方
② 演算子を多重定義するやり方

自分的にはソートしたいクラス内に静的メンバ関数でpredicadeを設定するのが楽でした。

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
 
using namespace std;

class MyData
{
public:
  static bool compareMyDataPredicate(MyData lhs, MyData rhs) { return (lhs.m_iData < rhs.m_iData); }
  // MyData中に入れ子にされたファンクタを宣言する
  struct compareMyDataFunctor : public binary_function<MyData, MyData, bool>
  {
      bool operator()( MyData lhs, MyData rhs)
      {
          return (lhs.m_iData < rhs.m_iData);
      }
  };

  int m_iData;
  string m_strSomeOtherData;
};

 
int main()
{
  // MyDataクラスの要素を含んだvector型の変数を作る
  vector<MyData> myvector;

  // vectorにデータを追加する
  MyData data;
  for(unsigned int i = 0; i < 10; ++i)
  {
    data.m_iData = i;
    myvector.push_back(data);
  }

  // 要素をランダムでシャッフルする
  std::random_shuffle(myvector.begin(), myvector.end());

  // vectorをpredicateとstd::sortを使ってソートする。この場合はpredicateは静的メンバ関数です
  std::sort(myvector.begin(), myvector.end(), MyData::compareMyDataPredicate);

  // vecorの中身を出力し確認する
  for (vector<MyData>::const_iterator citer = myvector.begin();
      citer != myvector.end(); ++citer)
  {
      cout << (*citer).m_iData << endl;
  }

  // ファンクタを使ってシャッフルとソートを行います。
  // その効果は同じですが、よりオブジェクト指向的なやり方でそれを行なっている点で少し異なります。
  std::random_shuffle(myvector.begin(), myvector.end());

  // predicateとstd::sortを使ったvectorをソートします。この場合はpredicateはファンクタです
  // ファンクタは構造体なのでコンストラクタの3つ目の引数として呼べます。
  std::sort(myvector.begin(), myvector.end(), MyData::compareMyDataFunctor());

  // vecorの中身を出力し確認する
  for (vector<MyData>::const_iterator citer = myvector.begin();
      citer != myvector.end(); ++citer)
  {
      cout << (*citer).m_iData << endl;
  }
  return 1;
}

C++11/14 コア言語

C++11/14 コア言語