Mike Irish
Mike Irish

Reputation: 960

C++ Sorting set using custom comparator in a container class

I have a class Person that has a name and an age.

I have a container class called people that stores a set of persons.

I have created two custom comparators to sort by name and by age.

When I store the set containing Persons in my class (People) how do pass the custom comparator in.

for Example

My comparator looks like this

struct compareByName
{
    bool operator()(const Person & Left, const Person & Right)
    {
        return (Left.getName() < Right.getName());
    }
};

in the main if I want to sort a set of persons by name I just do

set<Person, compareByName> peopleByName;

or for age I do

set<Person, compareByAge> peopleByAge;

Where I am having trouble is How do I use this in my people container class I would have something like

class People
{
private:
    set<Person, COMPARATOR> m_people;
}

where COMPARATOR could either be by name or age

Upvotes: 5

Views: 3155

Answers (2)

Slava
Slava

Reputation: 44238

You can use std::function as comparator type and then provide particular comparator for constructor:

class People
{
    using PeopleSet = set<Person, std::function<bool(const Person &p1, const Person &p2 )>>;

    People() : people( compareByName() ) {}
    void sortByAge();
private:
    PeopleSet people; 
};

note you cannot change comparator after creation of set, you have to create another instance:

void People::sortByAge()
{
    people = PeopleSet( people.begin(), people.end(), compareByAge() );
}

and that would involve copying or moving whole set. If you want to be able to use both ways at the same time use boost::multi_index instead.

Upvotes: 7

Killzone Kid
Killzone Kid

Reputation: 6240

You can do it via template:

#include <iostream>
#include <string>
#include <set>

class Person 
{
private:
    std::string name;
    int age;
public:
    Person(std::string name, int age) : name(name), age(age) {};
    std::string getName() const { return name; };
    int getAge() const { return age; };
};

template<class COMPARATOR> class People
{
private:
    std::set<Person, COMPARATOR> m_people;
public:
    void AddPerson(Person const &p)
    {
        m_people.insert(p);
    }
    void PrintPeople()
    {
        for (Person p : m_people)
        {
            std::cout << p.getName() << " - " << p.getAge() << std::endl;
        }
    }
};

struct SortedByName
{
    bool operator()(const Person & Left, const Person & Right)
    {
        return (Left.getName() < Right.getName());
    }
};

struct SortedByAge
{
    bool operator()(const Person & Left, const Person & Right)
    {
        return (Left.getAge() < Right.getAge());
    }
};


int main()
{
    Person p1("Bob", 21);
    Person p2("Jack", 13);
    Person p3("Kath", 33);

    People<SortedByName> ppl1;
    ppl1.AddPerson(p1);
    ppl1.AddPerson(p2);
    ppl1.AddPerson(p3);
    std::cout << "By Name:" << std::endl;
    ppl1.PrintPeople();

    std::cout << std::endl;

    People<SortedByAge> ppl2;
    ppl2.AddPerson(p1);
    ppl2.AddPerson(p2);
    ppl2.AddPerson(p3);
    std::cout << "By Age:" << std::endl;
    ppl2.PrintPeople();

    return 0;
}

Prints:

By Name:
Bob - 21
Jack - 13
Kath - 33

By Age:
Jack - 13
Bob - 21
Kath - 33

Upvotes: 2

Related Questions