olidev
olidev

Reputation: 20644

Sorting struct based on one of each property in C++

I am a Java and C# programmer. Recently, I am working on C++ project. I am having a problem of how to write the sample code following in C++. The sample code following is to sort a property of a struct:

public struct Person
{
    public string name;
    public int age;
}

Add some Persons to a list and sort by the age:

static void main()
{
   List<Person> persons = new List<Person>();

   Person person = new Person();
   person.age = 10;
   person.name = "Jane";

   persons.Add(person);

   person = new Person();
   person.age = 13;
   person.name = "Jack";

   persons.Add(person);

   person = new Person();
   person.age = 12;
   person.name = "Anna";

   persons.Add(person);

   // sort age
   persons.Sort(delegate(Person p1, Person p2) 
   { return p1.age.CompareTo(p2.age); });

   persons.ForEach(delegate(Person p) 
   { Console.WriteLine(String.Format("{0} {1}", p.age, p.name)); });
}

How can I write an equivalent sample code in C++?

Upvotes: 2

Views: 4110

Answers (2)

Dmitry Yudakov
Dmitry Yudakov

Reputation: 15734

Another option you have (instead of using list and reordering it by some criteria) could be using std::map (or std::multimap).

When putting them in map they are ordered by the key. std::map requires unique key, while std::multimap may many elements with same key.

// multimap< key, value >
std::multimap< int, Person* > IntOrderedMap;

IntOrderedMap ageOrder;

Person* p = new Person( "Jack", 13 );
ageOrder.insert( std::make_pair( p->age, p ) ); // use age as the map key

p = new Person( "Mike", 12 );
ageOrder.insert( std::make_pair( p->age, p ) );

p = new Person( "Paul", 13 );
ageOrder.insert( std::make_pair( p->age, p ) );

Then you can traverse it, the elements are ordered by the key (age)

for( IntOrderedMap::const_iterator it = ageOrder.begin(); it != ageOrder.end(); ++it )
{
    std::cout << it->second->Name << " is " << it->first << " years old" << std::endl;
}

Output:

Mike is 12 years old
Jack is 13 years old
Paul is 13 years old

This allows you at the same time to have another container where the persons are ordered by name.

std::multimap nameOrder;
for( IntOrderedMap::const_iterator it = ageOrder.begin(); it != ageOrder.end(); ++it )
{
    Person* p = it->second;
    nameOrder.insert( std::make_pair( p->name, p );
}

Upvotes: 1

icecrime
icecrime

Reputation: 76755

Given the Person type :

struct Person
{
    Person(int age_, const std::string &name_)
        : age(age_), name(name_)
    {}

    int age;
    std::string name;
};

int main()
{
    std::list<Person> persons;
    persons.push_back(Person(10, "Jane"));
    persons.push_back(Person(13, "Jack"));
    persons.push_back(Person(12, "Anna"));
}

Solution 1

bool compareAge(const Person &lhs, const Person &rhs)
{
    return lhs.age < rhs.age;
}

int main()
{
    /* persons list initialization */
    persons.sort(&compareAge);
}

Solution 2 (using boost::bind)

int main()
{
    /* persons list initialization */
    persons.sort(boost::bind(&Person::age, _1) < boost::bind(&Person::age, _2));
}

There also is a solution using C++0x lambdas.

Upvotes: 8

Related Questions