user3261013
user3261013

Reputation:

Sort STL list with single overloaded operator <

I have successfully populated linked list with data from a text file. Linked list contains structure that has 5 fields of type string.

I wish to sort the list by a certain structure field ( ascending or descending ). I have decided to overload operator< but I do not know how to implement it.

So far I am able to sort list by one fixed field. Here is the relevant code:

#include <iostream>       
#include <list>           // std::list
#include <fstream>        // std::ifstream, std::ofstream
#include <string>         // std::string
#include <algorithm>      // std::remove, std::remove_if
#include <sstream>        // std::istringstream

class Lista
{
private:
    struct Person
    {
        // data from file
        std::string lastName;  // other fields omitted for keeping brevity

        // operator < ( needed for correctly sorting the linked list )
        bool operator< ( const Person &p )const
        {
            return lastName > p.lastName;
        }

        // constructor / destructor ... omitted for keeping brevity 
    };

    // linked list that holds all the data from files
    std::list<Person> persons;

public:

// constructor / destructor ... omitted for keeping brevity

// method for sorting the list
    void sortList()
    {
        persons.sort();
    }
};

I would like to add enum of choices, so I can use only one overloaded operator< for sorting.

Something like this:

class Lista
{
private:
    struct Person
    {
        //================ here I could add enum of choices ============//

        enum choice { FIELD1, LASTNAME, FIELD2 }; // you get the point
        bool ascending;  // decides if it is ascending or descending

        //==============================================================//

        // data from file
        std::string lastName;  // other fields omitted for keeping brevity

        // operator < ( needed for correctly sorting the linked list )
        bool operator< ( const Person &p )const
        {
            if ( choice == FIELD1 )  
                return field1 < p.field1;

            if ( choice == FIELD2 )  
                return field2 < p.field2;

            if ( choice == LASTNAME )  
                 return lastName > p.lastName;
        }

        // constructor / destructor ... omitted for keeping brevity 
    };

    // linked list that holds all the data from files
    std::list<Person> persons;

public:

// constructor / destructor ... omitted for keeping brevity

// method for sorting the list
    void sortList( Person::choice ch, bool ascending)
    {
        // here I should use the parameters to invoke proper sorting 
        persons.sort();
    }

EDIT:

I have tried changing operator< into a function but have failed:

// this function is inside of my private struct
bool compare( const Person &p1, const Person &p2 )const
{
    return p1.lastName > p2.lastName;
}

Then I called it in method like this:

void sortList()
{
    persons.sort( compare );
}

But I get the following error: error C2065: 'compare' : undeclared identifier

I really have no other ideas on how to do this, can you please help me?

Upvotes: 2

Views: 1063

Answers (2)

Anmol Singh Jaggi
Anmol Singh Jaggi

Reputation: 8576

enum sort_choice { FIELD1, LASTNAME, FIELD2 } ; // had to put it outside to make it accessible to main()

class Lista
{

private:

    struct Person
    {
        std::string field1;
        std::string field2;
        std::string lastName;
        Person(const string& f1,const string& f2,const string& lname)
        {
            field1=f1;
            field2=f2;
            lastName=lname;
        }
    };

    struct cmp_Person  // A functor for comparison
    {
        bool cmp_ascending;
        sort_choice cmp_choice;

        cmp_Person(const bool& asc,const sort_choice& ch)
        {
            cmp_ascending=asc;
            cmp_choice=ch;
        }

        bool operator ()(const Person &first, const Person& second) const
        {
            if(cmp_ascending)
            {
                if ( cmp_choice == sort_choice::FIELD1 )
                    return first.field1 < second.field1;

                if ( cmp_choice == sort_choice::FIELD2 )
                    return first.field2 < second.field2;

                if ( cmp_choice == sort_choice::LASTNAME )
                    return first.lastName > second.lastName;
            }
            else
            {
                if ( cmp_choice == sort_choice::FIELD1 )
                    return first.field1 > second.field1;

                if ( cmp_choice == sort_choice::FIELD2 )
                    return first.field2 > second.field2;

                if ( cmp_choice == sort_choice::LASTNAME )
                    return first.lastName > second.lastName;
            }

            return true;
        }
    };

    std::list<Person> persons;

public:

    void sortList( const bool& ascending, const sort_choice& ch)
    {
        persons.sort(cmp_Person(ascending,ch));
    }

    void push_to_list(const string& f1,const string& f2,const string& lname)
    {
        persons.push_back(Person(f1,f2,lname));
    }

    void display_list()
    {
        list<Person>::iterator it;
        for(it=persons.begin(); it!=persons.end(); it++)
        {
            cout<<(*it).field1<<" "<<(*it).field2<<" "<<(*it).lastName<<"\n";
        }
    }
};


int main()
{
    Lista Lobj;
    Lobj.push_to_list("a","b","c");
    Lobj.push_to_list("d","e","f");
    Lobj.push_to_list("g","h","i");
    Lobj.push_to_list("j","k","l");
    Lobj.sortList(true,sort_choice::FIELD1);
    Lobj.display_list();
    cout<<"\n\n";
    Lobj.sortList(false,sort_choice::FIELD1);
    Lobj.display_list();
}

Upvotes: 2

uchar
uchar

Reputation: 2590

You can use something like this :

class Lista
{
public:
    enum class Sort_Type{Name,LastName};
    void sort(Sort_Type type,bool asc=true)
    {
        switch (type) {
        case Sort_Type::Name:
            this->list_.sort([&](const Person& p1,const Person& p2){
                if(asc)
                     return p1.name.compare(p2.name)>=0 ;
                else
                    return p1.name.compare(p2.name)<0;
            });
            break;
        case Sort_Type::LastName :
            this->list_.sort([&](const Person& p1,const Person& p2){

                if(asc)
                     return p1.lastName.compare(p2.lastName)>=0 ;
                else
                    return p1.lastName.compare(p2.lastName)<0;
            });
            break;
        }
    }

private:
    struct Person
    {
        string name ;
        string lastName;
    };

    std::list<Person> list_;
};

//
    Lista l;
    l.sort(Lista::Sort_Type::Name);

Upvotes: 0

Related Questions