tags:

views:

485

answers:

5

i want to sort a vector

vector<myclass> object;

where as myclass contains many int data variables, how can i sort my vector on any specific data variable of myclass.

+24  A: 
std::sort(object.begin(), object.end(), pred());

where, pred() is a function object defining the order on objects of myclass. Alternatively, you can define myclass::operator<.

The function object approach (v is the member on which you want to sort):

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

In C++0x, you can write

std::sort(object.begin(), object.end(),
    [](myclass const & a, myclass const &b){return a.v < b.v;});
avakar
can i define my criteria for the sort, can i tell sort according this variable?
NativeCoder
@NativeCoder that's what the operator is for - you can define it however you like and according to whatever variable you want. it's called Operator Overloading http://www.cs.caltech.edu/courses/cs11/material/cpp/donnie/cpp-ops.html.
Amir Rachum
The predicate approach is quite better than the operator overloading approach if you don't have a generic ordering of this particular class but just want to sort it for this vector.
Matthieu M.
+1  A: 

Use the std::sort algorithm function.

Klaim
+5  A: 

Overload less than operator, then sort. This is an example I found off the 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

gmcalab
You will want to make op<() const, and to pass its parameter as a const reference.
anon
-1 Posting stuff you "found on the web" is not what SO is about.
anon
@Neil, I posted the example I found because I didn't have time to type it all dude. IT was a solid example and solved the problem. I am glad it took you 40 mins to decide down-vote it. I could see it being down-voted if I didn't include the source site, but I did. It's not like I tried to pawn it off as my own.
gmcalab
I also downvoted it because it is wrong! And your edit hasn't improved it. If you don't know anything about C++, why answer C++ questions?
anon
@Neil I will admit it has been a while since I have used c++, but i remembered some general ideas with this question that's why I answered. I am not claiming it is perfect, but it does work, i tried it myself. I took your suggestion and added it. If you have some other problem with it, speak up instead acting so condescending. Acting like that is not was SO is about either dude.
gmcalab
@gmcalab: Your edit did not make `operator<` const. It made the return value const, which doesn't make much difference since it is a `bool` returned by value. As it is, you cannot use this comparison in situations where the left-hand operand is const.
Fred Larson
If you tried it and it "works" your compiler is broken. And please don't call me "dude".
anon
@gmcalab Your misunderstanding of what Neil meant by "make op<() const" demonstrates that you don't really understand the code you posted. Just because something "works" for you doesn't mean that it is the correct thing to do.
Tyler McHenry
@Neil sorry dude. I didn't try it with my const edits, my mistake. I'll take the heat for that one.
gmcalab
@Neil, it will work in this particular case, because elements of `myvector` are certainly non-const (otherwise you couldn't sort the vector).
avakar
@avakar Not with g++4.4.1. Just because the things being sorted are not const does not mean it is ok to apply non-const functions to them - or do you think sort can change the elements it sorts?
anon
@Neil, `sort` certainly can change elements of the sequence it sorts -- it wouldn't be able to sort it otherwise. What I missed, however, is that `std::less<T>::operator()` naturally takes its parameters by const reference, so you're right, the code was incorrect.
avakar
@avakar I guess I don't think of swapping as changing the elements :-)
anon
+3  A: 

A pointer-to-member allows you to write a single comparator, which can work with any data member of your class:

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

Output:

sorted by string field, c: x y
sorted by integer field, a: y x
sorted by integer field, b: x y
Steve Jessop
+3  A: 

Like explained in other answers you need to provide a comparison function. If you would like to keep the definition of that function close to the sort call (e.g. if it only makes sense for this sort) you can define it right there with boost::lambda. Use boost::lambda::bind to call the member function.

To e.g. sort by member variable or function 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));
honk