Reputation:
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();
}
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
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
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