2010-05-03 8 views

Répondre

61

Surcharge inférieure à l'opérateur, puis tri. Ceci est un exemple que je trouve 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: here

+13

Vous voudrez faire op <() const, et passer son paramètre en tant que référence const. –

+15

@Neil, j'ai posté l'exemple que j'ai trouvé parce que je n'ai pas eu le temps de taper tout mec. IT était un exemple solide et a résolu le problème. Je suis content qu'il vous ait fallu 40 minutes pour décider de voter. Je pourrais voir qu'il a été voté vers le bas si je n'incluais pas le site source, mais je l'ai fait. Ce n'est pas comme si j'avais essayé de le mettre en gage comme le mien. – Gabe

+7

@Neil J'admettrai que cela fait longtemps que j'ai utilisé le C++, mais je me suis souvenu de quelques idées générales avec cette question, c'est pourquoi j'ai répondu. Je ne prétends pas que c'est parfait, mais ça marche, je l'ai essayé moi-même. J'ai pris votre suggestion et l'ai ajoutée. Si vous avez un autre problème, parlez-en plutôt en agissant de manière condescendante. Agir comme ça ne l'était pas, c'est à propos de l'un ou l'autre mec. – Gabe

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

où, pred() est un objet de fonction définissant l'ordre sur les objets de myclass. Vous pouvez également définir myclass::operator<.

Par exemple, vous pouvez passer un lambda:

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

Ou si vous êtes coincé avec C++ 03, l'approche objet de fonction (v est l'élément sur lequel vous voulez trier):

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

@NativeCoder c'est ce que l'opérateur est pour - vous pouvez définir cependant vous aimez et selon n'importe quelle variable que vous voulez. C'est ce qu'on appelle la surcharge de l'opérateur http://www.cs.caltech.edu/courses/cs11/material/cpp/donnie/cpp-ops.html. –

+8

L'approche de prédicat est bien meilleure que l'approche de surcharge d'opérateur si vous n'avez pas un ordre générique de cette classe particulière mais voulez juste le trier pour ce vecteur. –

14

Un pointeur à membre vous permet d'écrire un seul comparateur, qui peut fonctionner avec un 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 
+0

Salut Steve, j'ai pensé à résoudre le même problème que cette question sans beaucoup de progrès! Votre solution me semble très bien. Je pense qu'il m'aurait fallu du temps pour le trouver, si jamais! J'ai lu C++ Effective C++ & Effective STL de Myers et C++ Common Knowledge de Dewhurst. Je me demande si vous pourriez recommander plus de lecture, connaissez-vous des livres qui couvrent des exemples comme celui ci-dessus en particulier ou, à défaut, des suggestions plus générales pour m'aider à voir des solutions comme ça? –

+1

@Czarak: en regardant à nouveau, il pourrait probablement être amélioré. Par exemple, il pourrait mieux optimiser si le pointeur vers le membre était un paramètre de modèle: 'modèle structure CompareByMember2 {opérateur booléen() (const T & lhs, const T & rhs) {return lhs. * F

+0

@Czarak: quant à la lecture, je ne suis pas sûr. Le "truc" ici est la combinaison de pointeurs membres avec des modèles, je pense que c'est une question d'être à l'aise d'écrire des modèles, et de savoir ce qui peut être fait avec eux. Le livre de Vandevoorde & Josuttis "C++ Templates - The Complete Guide" est censé être bon, mais je ne l'ai pas lu. Il pourrait être assez vieux et assez cher pour qu'il y ait une meilleure option maintenant. Regardez http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list. Et notez que si vous avez C++ 0x, une fonction lambda peut battre l'écriture de toute la classe pour cela! –

8

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

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

ceci est mon approche pour résoudre ce général. Il étend la réponse de Steve Jessop en supprimant l'obligation de définir des arguments de modèle explicitement et en ajoutant la possibilité d'utiliser également functoins et des pointeurs vers des 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; 
} 
Questions connexes