77 votes

comment trier le vecteur STL

je veux trier un vecteur

 vector<myclass> object;
 

où myclass contient de nombreuses variables de données int, comment puis-je trier mon vecteur sur une variable de données spécifique de myclass?

119voto

avakar Points 20031
 std::sort(object.begin(), object.end(), pred());
 

pred() est un objet fonction définissant l'ordre des objets de myclass . Alternativement, vous pouvez définir myclass::operator< .

L'approche objet de la fonction ( v est le membre sur lequel vous souhaitez trier):

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

En C ++ 0x, vous pouvez écrire

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

80voto

Gabe Points 24378

Surcharge moins que l'opérateur, puis triez. Ceci est un exemple que j'ai trouvé sur le web ...

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

Source: ici

15voto

Steve Jessop Points 166970

Un pointeur sur membre vous permet d'écrire un seul comparateur, qui peut fonctionner avec n'importe quel membre de données de votre classe:

 #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";
}
 

Sortie:

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

9voto

Benjamin Bannier Points 11953

Comme expliqué dans d'autres réponses, vous devez fournir une fonction de comparaison. Si vous souhaitez que la définition de cette fonction reste proche de l'appel sort (par exemple, si cela n'a de sens que pour ce type), vous pouvez la définir directement avec boost::lambda . Utilisez boost::lambda::bind pour appeler la fonction membre.

Pour par exemple trier par variable membre ou fonction 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));
 

2voto

Arne Points 866

C’est mon approche pour résoudre ce problème en général. Il étend la réponse de Steve Jessop en supprimant l'obligation de définir explicitement les arguments du modèle et en ajoutant l'option permettant également d'utiliser des fonctions et des pointeurs pour les méthodes (getters).

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X