2010-05-03 30 views
56

Ben sıralamak istiyorum myclass birçok int değişkenleri içeren bir vectorSTL vektörü nasıl sıralanır?

vector<myClass> object; 

. myClass'un belirli bir veri değişkeni üzerinde vector numaramı nasıl sıralayabilirim.

cevap

61

Operatörden daha az aşırı yükleme yapın, ardından sıralayın. Bu ... Ben web kapalı bulunan bir örnektir

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

Kaynak: here

+13

op <() const yapmak ve parametresini bir const reference olarak iletmek isteyeceksiniz. –

+15

@Neil, bulduğum örneği yolladım çünkü her şeyi yazacak vaktim yoktu. BT sağlam bir örnekti ve problemi çözdü. Onu oylamaya karar vermen 40 dakika sürdüğü için memnunum. Kaynak siteyi içermediysem oy kullanmamı görebiliyordum ama yaptım. Onu kendim gibi tamir etmeye çalışmamışım gibi değil. – Gabe

+7

@Neil C++ kullandığımdan beri bir süredir olduğunu itiraf edeceğim, ama bu soruyla bazı genel fikirleri hatırladım bu yüzden cevap verdim. Mükemmel olduğunu iddia etmiyorum, ama işe yarıyor, kendim denedim. Önerinizi aldım ve ekledim. Bununla ilgili başka bir probleminiz varsa, bunun yerine konuşmak o kadar küçümseyici davranın. Bunun gibi davranmak SO değil ya da dostum. – Gabe

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

, pred()myclass nesneler üzerinde sırasını tanımlayan bir fonksiyon amacıdır. Alternatif olarak, myclass::operator< tanımlayabilirsiniz. C++ 03 ile sıkışmış bir teklifi ise, fonksiyon nesne yaklaşımı (v sıralamak istediğiniz üyesidir)

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

:

Örneğin, bir lambda geçebilir

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

operatör bunun için var ekleyerek Steve Jessop cevabını uzanır - bunu tanımlayabilir Ancak istediğiniz ve istediğiniz herhangi bir değişkene göre. Operatör Aşırı Yüklemesi http://www.cs.caltech.edu/courses/cs11/material/cpp/donnie/cpp-ops.html olarak adlandırılmaktadır. –

+8

Bu belirli sınıfın genel bir sıralaması yoksa ancak sadece bu vektör için sıralamak istiyorsanız, tahmini yaklaşım, operatör aşırı yükleme yaklaşımından oldukça iyidir. –

14

işaretçi-için-üye Sınıfına herhangi bir veri üyesi ile çalışabilir tek karşılaştırıcı, yazmaya izin veren bir :

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

Çıktı:

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

Merhaba Steve, bu sorunun çok fazla ilerlemeden çözülmesini düşünüyorum! Çözümünüz bana çok yakışıyor. Sanırım, onunla gelmem uzun zaman almam gerekirdi! Myers'ın Etkin C++ ve Etkili STL ve Dewhurst'un C++ Ortak Bilgisini okudum. Biraz daha okumayı tavsiye edip edemeyeceğinizi merak ediyorum, özellikle yukarıdakiler gibi örnekleri kapsayan herhangi bir kitap biliyor musunuz ya da bu gibi çözümler görmeme yardımcı olacak daha genel önerilerden yoksun musunuz? –

+1

@Czarak: Tekrar bakmak gerekirse, muhtemelen iyileştirilebilir. Örneğin, üye işaretçisi şablon parametresiyse daha iyi duruma getirilebilir: 'template struct CompareByMember2 {bool operator() (const T & lhs, const T & rhs) {return lhs. * F

+0

@Czarak: okumaya gelince, emin değilim. Buradaki "numara", üye işaretçilerinin şablonlarla birleşimidir, bence bu, yazı şablonlarının rahat olması ve onlarla ne yapılabileceğini bilmektir. Vandevoorde & Josuttis'in “C++ Şablonları - Tam Kılavuz” kitabının iyi olması gerekiyordu ama okumadım. Şimdiye kadar daha iyi bir seçenek olması yeterince yaşlı ve pahalı olabilir. Http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list adresine bakın. Ve C++ 0x'iniz varsa, bir lambda fonksiyonu bunun için tüm sınıfı yazmayı yenebilir! –

8

gibi diğer cevaplar açıklandığı pro gerek karşılaştırma işlevi. , bu işlevin tanımını sort aramasına yakın tutmak istiyorsanız (ör. Sadece bu sıralama için anlamlıysa), boost::lambda ile tanımlayabilirsiniz. Üye işlevini çağırmak için boost::lambda::bind kullanın.

Örn. üye değişkeni ya da fonksiyon data1 göre sırala:

#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

bu genellikle bu çözmek için benim yaklaşımdır. Açıkça şablon argümanları ayarlamak için şartının kaldırılması ve ayrıca yöntemlere functoins ve işaretçileri kullanma seçeneğini (getters) o @NativeCoder

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