Sort by vector object members

I have these classes for a start:

Name ( string fName, string lName)
Student (Name name, int age)

Both classes classes have the < operator overloaded.

Now I have added a third class:

StudentContainer

StudentContainer creates a vector ”studentcontainer” with Student objects.

I need to sort the Student objects in the StudentContainer vector. I need to do it 2 ways:

SortByName
SortByAge

- - -
The < overload in the Student class:
1
2
//In Student.h
bool operator<(const Student &student) const; 


1
2
3
4
5
//In Student.cpp
bool::Student::operator<(const Student &student) const 
{
		return this->name < student.name;
}


The SortByName function in StudentContainer:
1
2
//In StudentContainer.h
void sortByName(); 


1
2
3
4
5
//In StudentContainer.cpp
void StudentContainer::sortByName() 
{
	sort(studentcontainer.begin(), studentcontainer.end());
}

- - -
This results in the studentcontainer objects being sorted by name using the overload of the Student < operator. So far so good.

The second version of sorting is supposed to be void and have no parameters:

void sortByAge();

I have not been able to figure out how to make this one work. The overloaded < in the Student class only does sorting by name. And since sortByAge() is required to be void and lack parameters, I can’t see how I could use a special function for sorting by age as a third parameter when calling sort() as I’ve seen suggested here for instance:

http://www.cplusplus.com/articles/NhA0RXSz/

That way to go seems to require both return type and parameters, rather than a void function with no parameters…

Any suggestions (preferably with code please)?
Last edited on
Your void StudentContainer::sortByAge() will call std::sort, won't it? It can pass to sort whatever it pleases.

The article that you did link to contains an example function:
1
2
// Sort Container by age function
bool sortByAge(const Person &lhs, const Person &rhs) { return lhs.age < rhs.age; }

Adapt to your types and give to sort.
Thanks. Well, in that example everything takes place within the same class/struct. In my case, I need to have the void sorting functions in the StudentContainer class, whereas a "bool SortByAge" would have to be in the Student class, correct? I don't currently see how I in a sorting function in the StudentContainer class can pass the bool sortByAge (Student class function) as an argument to std::sort?

Any further suggestions?
What is the interface of Student?
Student has its getters, including getAge(), if that is what you're hinting at. However, I don't see how I can access that through StudentContainer in a way that enables me to sort student objects in a studentcontainer object by age...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>
#include <string>
#include <utility>
#include <vector>
#include <algorithm>

using name_t = std::pair<std::string,std::string> ;

struct student
{
    name_t name_ ;
    int age_ ;

    std::string name() const { return name_.second + ", " + name_.first ; }
    int age() const { return age_ ; }
};

int main()
{
    using student_container_t = std::vector<student> ;

    student_container_t student_container =
    {
        { { "Stan", "Lippman" }, 21 },
        { { "Bjarne", "Stroustrup" }, 20 },
        { { "Andrew", "Koenig" }, 23 },
        { { "Jerry", "Schwartz" }, 19 },
        { { "Jim", "Coplien" }, 22 }
    };

    // sort on name
    std::sort( std::begin(student_container), std::end(student_container),
                []( student a, student b ) { return a.name() < b.name() ; } ) ;

    std::cout << "sorted on name\n--------------\n" ;
    for( student s : student_container )
        std::cout << s.name() << ' ' << s.age() << '\n' ;

    // sort on age
    std::sort( std::begin(student_container), std::end(student_container),
                []( student a, student b ) { return a.age() < b.age() ; } ) ;

    std::cout << "\nsorted on age\n--------------\n" ;
    for( student s : student_container )
        std::cout << s.age() << ' ' << s.name() << '\n' ;
}

http://coliru.stacked-crooked.com/a/50c16c1fe735218b
The other alternative is to augment the interface of a Student.
"operator<" is a name of a function. You can have other functions too:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
bool Student::nameIsBefore(const Student &student) const 
{
  return this->name < student.name;
}

bool Student::ageIsBefore(const Student &student) const 
{
  return this->age < student.age;
}

// for more completeness
bool::Student::operator<(const Student &student) const 
{
  if ( this->name == student.name )
    {
      return this->age < student.age;
    }
  else
    {
      return this->name < student.name;
    }
}


I would definitely go with the JLBorges' version.
Wow, thanks JLBorges and keskiverto!

I did it the keskiverto way adding more functions as it fits without re-designing the solution. Btw, you were spot on keskiverto, thanks for pointing out exactly what I was missing.

A couple of details to anyone who might read this thread:

1. I had to add the data type explicitly in the JLBorges code for it to compile using VS2013, as such:

 
{ name_t{ "Stan", "Lippman" }, 21 },
etc

2. going with keskiverto's solution (writing explicit compare functions to add as a third parameter to sort() ), the compare function couldn't be a member function

--> I had to make it a non-member function placing it outside of the class (or static, but that would have messed up in other ways)

--> I couldn't access the member data directly as in keskiverto's example, but rather I had to use the getters, as such:

1
2
3
4
bool sortAge(const Student &l, const Student &r) //See the aforementioned article
{
	return l.getAge() < r.getAge(); //Getters for access
}
Last edited on
That is good. If you did add those comparison functions to Student, then you could:
bool sortAge( const Student &l, const Student &r ) { return l.ageIsBefore( r ); }
Or with C++11 lambda syntax:
[]( const Student & a, const Student & b ) { return a.ageIsBefore( b ); }
Topic archived. No new replies allowed.