2010-05-03 6 views

답변

61

연산자보다 작고 오버로드 된 다음 정렬합니다. 이 ... 내가 웹을 발견 한 예이다

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

+13

op <() const를 만들고 해당 매개 변수를 const 참조로 전달하고자 할 것입니다. –

+15

@Neil, 나는 모든 친구를 타이핑 할 시간이 없었기 때문에 내가 찾은 예제를 게시했다. IT는 견고한 모범이었고 문제를 해결했습니다. 나는 투표를 결정하기 위해 40 분이 걸렸기 때문에 기쁩니다. 나는 소스 사이트를 포함시키지 않으면 다운 투표를 볼 수 있었지만 그렇게했다. 나는 그것을 내 자신의 것으로 추론하려하지 않았다. – Gabe

+7

@Neil 나는 C++을 사용한 이후로 꽤 오래 됐음을 인정할 것이다. 그러나 나는이 질문에 대한 몇 가지 일반적인 아이디어를 기억해 냈다. 그래서 나는 대답했다. 나는 그것이 완벽하다고 주장하지는 않지만 작동하지만, 나는 그것을 스스로 시도했다. 나는 너의 제안을 받아 추가했다. 당신이 다른 문제가 있다면, 대신 그렇게 말하다. 그 것처럼 행동하는 것은 SO에 관한 것입니다. – Gabe

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

, pred()myclass 물체의 순서를 정의하는 기능 오브젝트이다. 또는 myclass::operator<을 정의 할 수 있습니다. 당신이 C++ 03와 함께 붙어있는 경우 또는 함수 객체 접근 (v 당신이 정렬하려는 구성원 인)

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

:

예를 들어, 람다를 전달할 수 있습니다

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

운영자가입니다 무엇을 추가하여 스티브 Jessop에서 답을 확장 - 당신은 그것을 정의 할 수 있습니다 그러나 당신은 무엇이든 원하는 변수에 따라 좋아합니다. 연산자 오버로딩 (Operator Overloading)이라고합니다. http://www.cs.caltech.edu/courses/cs11/material/cpp/donnie/cpp-ops.html. –

+8

이 특정 클래스의 일반적인 순서가 없지만이 벡터에 대해 정렬하기 만하면 연산자 오버로드 접근법보다 술어 접근법이 훨씬 좋습니다. –

14

포인터 - 투 - 멤버는 클래스의 데이터 멤버와 함께 작업 할 수있는 하나의 비교기를 쓸 수 있도록하는 :

#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 
+0

안녕하세요, 스티브, 저는이 문제와 같은 문제를 많은 진전없이 해결하려고 생각해 왔습니다! 당신의 솔루션은 나에게 아주 좋아 보인다. 나는 그것이 오랜 시간이 걸릴 것이라고 생각한다. Myers의 Effective C++ 및 Effective STL과 Dewhurst의 C++ Common Knowledge를 읽었습니다. 나는 당신이 좀 더 독서를 추천 할 수 있는지 궁금하다. 특히 위에있는 것과 같은 예를 다루는 책을 알고 있는가? 아니면 그런 해결책을 볼 수있는 더 일반적인 제안을하지 못하는가? –

+1

@Czarak : 다시 보니 개선 될 수 있습니다. 예를 들어 멤버에 대한 포인터가 템플릿 매개 변수 인 경우 최적화가 더 잘됩니다 : template 구조체 CompareByMember2 {bool operator() (const T & lhs, const T & rhs) {return lhs. * F

+0

@Czarak : 독서로는 확실하지 않습니다. 여기에있는 "트릭"은 템플릿과 멤버 포인터의 조합입니다. 필자는 템플릿을 작성하는 것이 쉽고, 무엇을 할 수 있는지 아는 것이 중요하다고 생각합니다. Vandevoorde & Josuttis의 저서 "C++ Templates - The Complete Guide"는 좋겠지 만 읽지는 않았습니다. 충분히 오래되고 충분히 비싸기 때문에 지금까지는 더 좋은 선택이 될 수 있습니다. http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list를 참조하십시오. C++ 0x를 사용하면 람다 함수가 전체 클래스를 작성하는 데 도움이 될 수 있습니다. –

8

처럼 다른 답변에서 설명 당신은 프로 필요 비교 기능을 제공하십시오. 해당 기능의 정의를 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)); 
2

이것은 일반적으로이를 해결하기위한 나의 접근 방법입니다. 그것은 명시 적으로 템플릿 인수를 설정하는 요구 사항을 제거하고 또한 방법에 functoins 및 포인터를 사용하는 옵션 (게터)이 @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; 
} 
관련 문제