如何排序STL向量?


76

我想排序一个 vector

vector<myClass> object;

其中myclass包含许多int变量。如何vector对的任何特定数据变量进行排序myClass

Answers:


80

重载少于运算符,然后排序。这是我在网上发现的一个例子...

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

资料来源:这里


14
您将需要使op <()成为const,并将其参数作为const引用传递。

19
@Neil,我发布了发现的示例,因为我没有时间键入所有花花公子。IT是一个很好的例子,解决了这个问题。很高兴您花了40分钟的时间才决定是否投票。如果不包括源站点,我可以看到它被否决了,但是我做到了。这并不是我试图自己当兵。
加布

9
@Neil我承认使用c ++已经有一段时间了,但是我记得这个问题的一些一般性想法,这就是我回答的原因。我并不是说它是完美的,但是它确实有效,我自己尝试过。我接受了您的建议并添加了它。如果您还有其他问题,请大声疾呼。像那样行事不是SO左右。
加布

4
如果您尝试过并且可以“运行”,则说明编译器已损坏。而且请不要称我为“花花公子”。

2
@gmcalab您对Neil的“ make op <()const”含义的误解表明您并不真正理解所发布的代码。仅仅因为某些事情对您有用,并不意味着它是正确的事情。
泰勒·麦克亨利

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

其中,pred()是定义的对象顺序的函数对象myclass。或者,您可以定义myclass::operator<

例如,您可以传递一个lambda:

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

或者,如果您对C ++ 03感到困惑,则可以使用函数对象方法(v要对其进行排序的成员):

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

@NativeCoder就是运算符的作用-您可以根据需要定义它,并根据所需的任何变量进行定义。称为运算符重载cs.caltech.edu/courses/cs11/material/cpp/donnie/cpp-ops.html
Amir Rachum'5

8
如果您没有该特定类的一般顺序,而只想对该向量进行排序,则谓词方法比运算符重载方法要好得多。
Matthieu M.

15

指向成员的指针使您可以编写一个比较器,该比较器可以与您的类的任何数据成员一起使用:

#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

嗨,史蒂夫,我一直在考虑解决与此问题相同的问题,但没有太大的进展!您的解决方案对我来说很好。我想,如果有的话,我会花很长时间来提出它!我已经阅读了Myers的有效C ++和有效STL和Dewhurst的C ++常识。我想知道您是否可以推荐更多的阅读内容,您是否知道其中有任何本书涵盖了像您上面的例子那样的书,或者是否没有任何其他更一般的建议可以帮助我找到类似的解决方案?
Paul Caheny 2010年

1
@Czarak:再来看一看,可能会得到改善。例如,如果指向member的指针是模板参数,则可能会优化得更好template <typename T, typename U, U (T::*F)> struct CompareByMember2 { bool operator()(const T &lhs, const T & rhs) { return lhs.*F < rhs.*F; }};。是否可行取决于调用方是使用变量进行成员排序,还是由不同的调用者指定不同的特定成员。
史蒂夫·杰索普

@Czarak:至于阅读,我不确定。这里的“技巧”是成员指针与模板的结合,我认为这是舒适地编写模板并知道可以使用它们完成的事情。Vandevoorde&Josuttis的书“ C ++模板-完整指南”应该不错,但是我还没有读过。它可能已经够老了而且很昂贵,以至于现在有一个更好的选择。查看stackoverflow.com/questions/388242/…。请注意,如果您使用的是C ++ 0x,则lambda函数可能胜过为此编写整个类!
史蒂夫·杰索普

您好史蒂夫,感谢您提供的非常有用的答案。我一直按照您的建议研究lambda函数,这导致了另一个问题,如果我按照上面答案中的建议提出解决方案,我相信我也会遇到。如果您能抽出时间,也许可以看看?stackoverflow.com/questions/4268848/…–
保罗·卡尼

我发现,当您提供创建模板对象实例的函数时,可以将调用函数简化为“ sort(begin(vec),end(vec),by_member(&Test :: c));”)。
Arne 2014年

9

就像其他答案中解释的那样,您需要提供比较功能。如果您想使该函数的定义接近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和方法的指针(getter)的选项,从而扩展了Steve Jessop的答案。

#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;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.