2010-05-03 12 views

Antwort

61

Überlastung weniger als Operator, dann sortieren. Dies ist ein Beispiel, das ich im Internet gefunden off ...

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

Quelle: here

+13

Sie wollen op <() const machen und seinen Parameter als const-Referenz übergeben. –

+15

@Neil, ich habe das Beispiel gepostet, das ich gefunden habe, weil ich keine Zeit hatte, alles zu tippen, Alter. IT war ein solides Beispiel und löste das Problem. Ich bin froh, dass du 40 Minuten gebraucht hast, um dich zu entscheiden. Ich könnte sehen, dass es abgelehnt wird, wenn ich die Quellseite nicht mit einbeziehe, aber ich habe es getan. Es ist nicht so, dass ich versucht habe, es als mein eigenes zu verpfänden. – Gabe

+7

@Neil Ich gebe zu, es ist eine Weile her, seit ich C++ benutzt habe, aber ich erinnerte mich an einige allgemeine Ideen mit dieser Frage, deshalb habe ich geantwortet. Ich behaupte nicht, dass es perfekt ist, aber es funktioniert, ich habe es selbst ausprobiert. Ich nahm Ihren Vorschlag und fügte es hinzu. Wenn Sie ein anderes Problem damit haben, sprechen Sie stattdessen so herablassend. So zu handeln ist nicht, dass SO über irgendjemanden ist. – Gabe

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

wo pred() ist eine Objektfunktion auf die Reihenfolge der Objekte myclass definieren. Alternativ können Sie myclass::operator< definieren.

Zum Beispiel können Sie eine Lambda-Pass:

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

Oder wenn Sie mit C++ 03 stecken, die Funktion Objekt-Ansatz (v das Element, auf dem Sie sortieren möchten):

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

@NativeCoder das ist zu verwenden, was der Betreiber ist - man kann es definieren wie auch immer du magst und nach welcher Variable du willst. es heißt Operator Overloading http://www.cs.caltech.edu/courses/cs11/material/cpp/donnie/cpp-ops.html. –

+8

Der Prädikat-Ansatz ist ziemlich besser als der Operator-Überladungsansatz, wenn Sie keine generische Anordnung dieser bestimmten Klasse haben, sondern nur nach diesem Vektor sortieren möchten. –

14

Ein Zeiger-to-Mitglied kann Ihnen einen einzigen Komparator schreiben, die mit jedem Datenelement der Klasse arbeiten können :

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

Ausgang:

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

Hallo Steve, ich habe darüber nachgedacht, das gleiche Problem wie diese Frage ohne viel Fortschritt zu lösen! Deine Lösung sieht sehr gut aus. Ich denke, es hätte lange gedauert, bis ich dazu gekommen wäre. Ich habe Myers 'Effektives C++ & Effektives STL und Dewursts C++ - Allgemeinwissen gelesen. Ich frage mich, ob Sie etwas mehr Lesen empfehlen könnten, wissen Sie von irgendwelchen Büchern, die Beispiele wie Ihre oben besonders bedecken, oder versäumend, dass allgemeinere Vorschläge, um mir zu helfen, solche Lösungen zu sehen? –

+1

@Czarak: wenn ich es nochmal ansehe, könnte es wahrscheinlich verbessert werden. Zum Beispiel könnte es besser optimieren, wenn der Zeiger zum Mitglied ein Vorlagenparameter war: 'Vorlage Struktur CompareByMember2 {Booloperator() (const T & lhs, const T & rhs) {zurück lhs. * F

+0

@Czarak: wie zum Lesen, bin ich mir nicht sicher. Der "Trick" ist hier die Kombination von Member-Zeigern mit Templates. Ich denke, es ist eine Frage der Bequemlichkeit, Templates zu schreiben und zu wissen, was mit ihnen gemacht werden kann. Vandevoordes & Josuttis 'Buch "C++ Templates - The Complete Guide" soll gut sein, aber ich habe es nicht gelesen. Es könnte alt genug und teuer genug sein, dass es jetzt eine bessere Option gibt. Sehen Sie sich http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list an. Und beachte, dass eine Lambda-Funktion, wenn du C++ 0x hast, die gesamte Klasse dafür schlagen könnte! –

8

Wie in anderen Antworten erklärt müssen Sie pro vide eine Vergleichsfunktion. Wenn Sie möchten, dass die Definition dieser Funktion in der Nähe des sort Aufruf (z. B. wenn es nur für diese Art sinnvoll ist) Sie können es genau dort mit boost::lambda definieren. Verwenden Sie boost::lambda::bind, um die Elementfunktion aufzurufen.

z.B. sortiert nach Membervariable oder Funktion 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

das ist mein Ansatz dies in der Regel zu lösen. Es erstreckt sich die Antwort von Steve Jessop durch die Anforderung Vorlage Argumente explizit festlegen Entfernen und Hinzufügen der Möglichkeit, auch functoins und Zeiger auf Methoden (Getter)

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