8

say I have a class "Information" and it stores the Name and Age of people in a vector.

so...

class Information {

private:
int age;
string name;

//etc, etc...
};

How would I sort the vector in either ascending/descending order with respect to age?

I believe you use something like this.

sort(listOfPeople.begin(), listOfPeople.end(), greater<Information>());

listOfPeople would be the vector.

Any help would be greatly appreciated.

6 Answers 6

6

If you want to sort them in non-descending order by age, one way to do it is to define a functor for comparison:

class CompareInformations {
    public:
    // after making CompareInformations a friend class to Information...
    operator(const Information& rhs, const Information& lhs) {
        return rhs.age < lhs.age;
    }
};

And then do your sort:

sort(listOfPeople.begin(), listOfPeople.end(), CompareInformations());

You could also overload operator< for your class, and do without the comparison object:

// inside your class
bool operator <(const Information& rhs) {
    return age < rhs.age;
}

Then sort it:

sort(listOfPeople.begin(), listOfPeople.end());

The above examples assume you want to sort in non-descending (almost ascending, but not quite) order. To do non-ascending order, just change all occurrences of < to >.

Sign up to request clarification or add additional context in comments.

9 Comments

What do you mean by making CompareInformations a friend class to Information?
@Vincent as you have it, age is a private variable and the class CompareInformations accesses that variable. That would give you an error because that's not allowed. However, if you put friend class CompareInformations; somewhere in the definition of Information, you'll let CompareInformations access the private members of that class. Or you could just replace the accesses to rhs.age and stuff with rhs.getAge() or whatever accessor you have defined.
Yep, I used rhs.getAge(). I attempted it however I get the following error message when attempting to compile. error: passing 'const Information' as 'this' argument of 'int Information::getAge()' discards qualifiers testone.cpp
@Vincent yeah, have you tried marking the getAge method as const? Only const functions can be called on const objects. That, or remove the const from the arguments of the comparison functions.
@Vincent You should take a look at the C++ FAQ: Const correctness, especially What is a "const member function"?. In fact read through the entire FAQ when you have some time, it's an excellent resource.
|
4

You need to create a comparator function or functor class that takes two Information references and returns true if the first should be ordered before the second.

The following will sort from oldest to youngest:

bool CompareAges(const Information & left, const Information & right)
{
    return left.age > right.age;
}

std::sort(listOfPeople.begin(), listOfPeople.end(), CompareAges);

To select whether to sort ascending or descending, you can have two different calls to sort with different comparison functions, or you can create a functor class that has a flag determining how the items should be sorted.

struct CompareAgesUpOrDown
{
    CompareAgesUpOrDown(bool bDown) : m_bDown(bDown) {}
    bool operator() (const Information & left, const Information & right)
    {
        if (m_bDown)
            return left.age < right.age;
        else
            return left.age > right.age;
    }
    bool m_bDown;
};

bool bDown = ...;
std::sort(std::sort(listOfPeople.begin(), listOfPeople.end(), CompareAgesUpOrDown(bDown));

6 Comments

I'm not sure if I'm doing it correctly but attempting to implement the first block of code gives me the following output when trying to compile.testone.cpp:27: error: passing 'const Information' as 'this' argument of 'int Information::getAge()' discards qualifiers testone.cpp:27: error: passing 'const Information' as 'this' argument of 'int Information::getAge()' discards qualifiers
Sorry, I'm fairly new at this. How exactly would I mark getAge as const ?
You mark a function as const by putting const at the end of the function prototype: int getAge() const. By doing that you are "promising" that function will not modify any members of the class to which it belongs.
I got it. Thank you so much for your help. I assume this would also work for comparing time_t as opposed to int? Again, thanks!
@Vincent yes, you're correct, since time_t is an integral type (it's some kind of a number).
|
4

Others have already shown C++98/03 solutions. In C++11, you might want to use a lambda for your comparison instead:

// ascending age:
std::sort(people.begin(), people.end(), 
          [](person const &a, person const &b) { return a.age < b.age; });

// descending age:
std::sort(people.begin(), people.end(), 
          [](person const &a, person const &b) { return b.age < a.age; });

And, in case it should happen to arise:

// ascending name:
std::sort(people.begin(), people.end(), 
          [](person const &a, person const &b) { return a.name < b.name; });

// descending name:
std::sort(people.begin(), people.end(), 
          [](person const &a, person const &b) { return b.name < a.name; });

IMO, Information is too generic a name, so I've changed it to person. Contrariwise, listOfPeople puts too much emphasis on the form rather than the content (and, worse, it's just plain wrong, since you really have a vector of people, not a list at all). IMO, in programming, it's generally better to use list only to refer to a linked list, not to linear data structures in general.

2 Comments

Thanks, I will keep your tips in mind. Just a question, I assume you do not need the bool comparing function if you implement it this way? I will try out this code when I get home.
@Vincent: yes. A lambda lets you specify the comparison code inline instead of separately. FWIW, if you're usually using one ordering, you probably want to put that into the class' operator<, and only explicitly specify the order for other cases.
1

You need to have a comparison function or object in order to use that sort. Take a look at the sort page at cplusplus.com for examples and information.

Here's a complete example using a comparison function:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

class Information {
public:
  Information(int age, std::string name) : m_age(age), m_name(name) {}
  int age() const { return m_age; }
  std::string name() const { return m_name; }
private:
  int m_age;
  std::string m_name;

  friend bool sortInformationByAgeAscending(const Information& lhs, 
                                            const Information& rhs);      
  friend bool sortInformationByAgeDescending(const Information& lhs, 
                                             const Information& rhs);
};

bool sortInformationByAgeAscending(const Information& lhs, 
                                   const Information& rhs) {
  return lhs.m_age < rhs.m_age;
}

bool sortInformationByAgeDescending(const Information& lhs, 
                                    const Information& rhs) {
  return lhs.m_age > rhs.m_age;
}
int main (int argc, const char * argv[])
{
  std::vector<Information> info;
  info.push_back(Information(1, "Bill"));
  info.push_back(Information(5, "Ann"));
  info.push_back(Information(2, "Sue"));

  std::sort(info.begin(), info.end(), sortInformationByAgeAscending);

  std::cout << info.at(0).age() << ": " << info.at(0).name() << std::endl;
  std::cout << info.at(1).age() << ": " << info.at(1).name() << std::endl;
  std::cout << info.at(2).age() << ": " << info.at(2).name() << std::endl;

  return 0;
}

Comments

0

I would overload operator < and then sort using greater. Greater essentially means rhs < lhs. You then sort using sort(listOfPeople.begin(), listOfPeople.end(), greater<Information>());

If you decide to add operator< your class would play nicely with std::set and as a key in std::map in addition to allowing sort.

class Information {

private:
int age;
string name;

friend bool operator< (Information const& lhs, Information const& rhs){
    return lhs.age < rhs.age;
}

//etc, etc...
};

2 Comments

Any reason this is a friend function rather than a member function?
Force of habit. I normally deal with arithmetic types and want the free functions to benefit from conversion.
0

For descending sort you must overload > operator and not < then call sort with greater option like this : sort(listOfPeople.begin(), listOfPeople.end(), greater<Information>());

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.