web-dev-qa-db-ja.com

STLベクターをソートするには?

vectorを並べ替えたい

vector<myClass> object;

myclassには多くのint変数が含まれます。 vectorの特定のデータ変数でmyClassをソートするにはどうすればよいですか。

73
NativeCoder

小なり演算子をオーバーロードしてから、ソートします。これは私がウェブから見つけた例です...

class MyData
{
public:
  int m_iData;
  string m_strSomeOtherData;
  bool operator<(const MyData &rhs) const { return m_iData < rhs.m_iData; }
};

std::sort(myvector.begin(), myvector.end());

ソース: here

76
Gabe
std::sort(object.begin(), object.end(), pred());

ここで、pred()は、myclassのオブジェクトの順序を定義する関数オブジェクトです。または、myclass::operator<を定義できます。

たとえば、ラムダを渡すことができます。

std::sort(object.begin(), object.end(),
          [] (myclass const& a, myclass const& b) { return a.v < b.v; });

または、C++ 03にこだわっている場合、関数オブジェクトアプローチ(vはソートするメンバーです):

struct pred {
    bool operator()(myclass const & a, myclass const & b) const {
        return a.v < b.v;
    }
};
112
avakar

メンバーへのポインターを使用すると、クラスの任意のデータメンバーと連携できる単一のコンパレーターを記述できます。

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

template <typename T, typename U>
struct CompareByMember {
    // This is a pointer-to-member, it represents a member of class T
    // The data member has type U
    U T::*field;
    CompareByMember(U T::*f) : field(f) {}
    bool operator()(const T &lhs, const T &rhs) {
        return lhs.*field < rhs.*field;
    }
};

struct Test {
    int a;
    int b;
    std::string c;
    Test(int a, int b, std::string c) : a(a), b(b), c(c) {}
};

// for convenience, this just lets us print out a Test object
std::ostream &operator<<(std::ostream &o, const Test &t) {
    return o << t.c;
}

int main() {
    std::vector<Test> vec;
    vec.Push_back(Test(1, 10, "y"));
    vec.Push_back(Test(2, 9, "x"));

    // sort on the string field
    std::sort(vec.begin(), vec.end(), 
        CompareByMember<Test,std::string>(&Test::c));
    std::cout << "sorted by string field, c: ";
    std::cout << vec[0] << " " << vec[1] << "\n";

    // sort on the first integer field
    std::sort(vec.begin(), vec.end(), 
        CompareByMember<Test,int>(&Test::a));
    std::cout << "sorted by integer field, a: ";
    std::cout << vec[0] << " " << vec[1] << "\n";

    // sort on the second integer field
    std::sort(vec.begin(), vec.end(), 
        CompareByMember<Test,int>(&Test::b));
    std::cout << "sorted by integer field, b: ";
    std::cout << vec[0] << " " << vec[1] << "\n";
}

出力:

sorted by string field, c: x y
sorted by integer field, a: y x
sorted by integer field, b: x y
15
Steve Jessop

他の回答で説明したように、比較関数を提供する必要があります。その関数の定義をsort呼び出しの近くに保持したい場合(たとえば、この並べ替えにのみ意味がある場合)、boost::lambdaを使用してすぐに定義できます。 boost::lambda::bindを使用して、メンバー関数を呼び出します。

例えばメンバー変数または関数data1で並べ替え:

#include <algorithm>
#include <vector>
#include <boost/lambda/bind.hpp>
#include <boost/lambda/lambda.hpp>
using boost::lambda::bind;
using boost::lambda::_1;
using boost::lambda::_2;

std::vector<myclass> object(10000);
std::sort(object.begin(), object.end(),
    bind(&myclass::data1, _1) < bind(&myclass::data1, _2));
9

これは、これを一般的に解決するための私のアプローチです。テンプレートの引数を明示的に設定する要件を削除し、functoinsとメソッドへのポインター(ゲッター)を使用するオプションを追加することにより、Steve Jessopからの回答を拡張します。

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

using namespace std;

template <typename T, typename U>
struct CompareByGetter {
    U (T::*getter)() const;
    CompareByGetter(U (T::*getter)() const) : getter(getter) {};
    bool operator()(const T &lhs, const T &rhs) {
        (lhs.*getter)() < (rhs.*getter)();
    }
};

template <typename T, typename U>
CompareByGetter<T,U> by(U (T::*getter)() const) {
    return CompareByGetter<T,U>(getter);
}

//// sort_by
template <typename T, typename U>
struct CompareByMember {
    U T::*field;
    CompareByMember(U T::*f) : field(f) {}
    bool operator()(const T &lhs, const T &rhs) {
        return lhs.*field < rhs.*field;
    }
};

template <typename T, typename U>
CompareByMember<T,U> by(U T::*f) {
    return CompareByMember<T,U>(f);
}

template <typename T, typename U>
struct CompareByFunction {
    function<U(T)> f;
    CompareByFunction(function<U(T)> f) : f(f) {}
    bool operator()(const T& a, const T& b) const {
        return f(a) < f(b);
    }
};

template <typename T, typename U>
CompareByFunction<T,U> by(function<U(T)> f) {
    CompareByFunction<T,U> cmp{f};
    return cmp;
}

struct mystruct {
    double x,y,z;
    string name;
    double length() const {
        return sqrt( x*x + y*y + z*z );
    }
};

ostream& operator<< (ostream& os, const mystruct& ms) {
    return os << "{ " << ms.x << ", " << ms.y << ", " << ms.z << ", " << ms.name << " len: " << ms.length() << "}";
}

template <class T>
ostream& operator<< (ostream& os, std::vector<T> v) {
    os << "[";
    for (auto it = begin(v); it != end(v); ++it) {
        if ( it != begin(v) ) {
            os << " ";
        }
        os << *it;
    }
    os << "]";
    return os;
}

void sorting() {
    vector<mystruct> vec1 = { {1,1,0,"a"}, {0,1,2,"b"}, {-1,-5,0,"c"}, {0,0,0,"d"} };

    function<string(const mystruct&)> f = [](const mystruct& v){return v.name;};

    cout << "unsorted  " << vec1 << endl;
    sort(begin(vec1), end(vec1), by(&mystruct::x) );
    cout << "sort_by x " << vec1 << endl;
    sort(begin(vec1), end(vec1), by(&mystruct::length));
    cout << "sort_by len " << vec1 << endl;
    sort(begin(vec1), end(vec1), by(f) );
    cout << "sort_by name " << vec1 << endl;
}
2
Arne