Sorting a list, vector<struct>

Hi,
I'm trying to alphabetically sort a vector of structures based on the last name(if the last name matches sort on first name). But when I do this I get like 20 error messages. What am I doing wrong?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
struct Person
{
    string firstname;
    string lastname;
    float length;
};

void sort(const vector<Person>& persons)
{
    sort( persons.begin( ), persons.end( ), [ ]( const Person& lhs, const Person& rhs )
    {
        return lhs.lastname < rhs.lastname;
    });
        
    
    for(auto& e : persons)
    {
        cout << right << setw(20) << e.firstname;
        cout << setw(20) << e.lastname;
        cout << right << setw(5) << e.length << endl;
    }
}


If the last name are equal maybe something similar to this will work,
1
2
3
4
5
6
7
if(lastname==lastname)
    {
        sort( persons.begin( ), persons.end( ), [ ]( const Person& lhs, const Person& rhs )
             {
                 return lhs.firstname < rhs.firstname;
             });
    }
Here is a code snippet from a program I did a while ago that sorted by last name using shell sort.

The sort function
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
void ShellSort(vector<Employee> &V)
{
	bool flag = true;
	int i, numLength = (V.size() / 5);

	int d = numLength;
	while (flag || (d>1))    // bool flag 
	{
		flag = false;  //reset flag to 0 to check for
					   // future swaps     
		d = (d + 1) / 2;
		for (i = 0; i < (numLength - d); i++)
		{
			if (V[i + d].last < V[i].last)
			{
				swapper(V[i].last, V[i + d].last);
				swapper(V[i].first, V[i + d].first);
				swapper(V[i].empNum, V[i + d].empNum);
				swapper(V[i].dep, V[i + d].dep);
				swapper(V[i].salary, V[i + d].salary);

				flag = true;     //tells swap has occurred
			}
		}
	}
}


swapper function
1
2
3
4
5
6
7
8
9
//templated swap function
template<class CType>
void swapper(CType& a, CType& b)
{
	CType temp;
	temp = a;
	a = b;
	b = temp;
}


Hope this helps
Last edited on
markusfirst, are you sure your compiler has C++11 support enabled?

As for changing the sort criteria to sort based on the first name if the last names are identical, that's something to do in the lambda within lines 11-13 of the snippet.

-Albatross
Sorting re-arranges the vector, so you can't pass a const vector to the function. Also, if you pass by reference it sorts the actual vector, not a copy, so if you run coutlist() after sort() it will print out the sorted vector. To keep original vector unchanged pass a copy to the sort function:
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#include <iostream> // cout, cin
#include <iomanip> // setw, left, right
#include <string> // strängar
#include <vector> // std::vector
#include <limits>
#include <algorithm>
using namespace std;

bool yesOrNo(string str);

struct Person
{
    string firstname;
    string lastname;
   // float length;
};

void addname(vector<Person>& persons);
void coutlist(vector<Person> persons);
void searchperson(const vector<Person>& persons);
void sortperson(vector<Person> persons);

int main()
{
    vector<Person> persons;
    bool again = true;
    char ch;
    do
    {
        cout << endl << "Programmenu" << endl << endl;
        cout << "1 Add name" << endl;
        cout << "2 Write out the list" << endl;
        cout << "3 Search \n";
        cout << "4 Sort \n";
        cout << "5 End" << endl;
        cin >> ch;
        cin.clear();
        cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

        switch(ch)
        {
            case '1':
                addname(persons);
                break;
            case '2':
                coutlist(persons);
                break;
            case '3':
                searchperson(persons);
                break;
            case '4':
                sortperson(persons);
                break;
            case '5':
                again = false;
            default:
                break;
        }
    }while(again);

    return 0;
}

//----------------------------------------------------------------------------
//Write out list
//----------------------------------------------------------------------------

void coutlist(vector<Person> persons)
{
    cout << endl << "First name, Last name" << endl<<endl;
    for(auto& e : persons)
    {
        cout << left << setw(20) << e.firstname;
        cout << setw(20) << e.lastname;
    }
    cout << endl;
}

//----------------------------------------------------------------------------
//Add name
//----------------------------------------------------------------------------

void addname(vector<Person>& persons)
{
    do
    {
        Person tmpPerson;
        cout << endl;
        cout << "Input data for a person!" << endl;
        cout << "Name : ";
        getline(cin,tmpPerson.firstname);
        cout << "Lastname : ";
        getline(cin,tmpPerson.lastname);
        persons.push_back(move(tmpPerson));


    }while(yesOrNo("One more person? (y/n): "));

    return;
}
void searchperson(const vector<Person>& persons)
{
    string searchName;
    cout << "Enter first name to search by\n";
    cin >> searchName;
    auto pred = [searchName](const Person & item)
    {
        return item.firstname == searchName;
    };

    auto itr = std::find_if(std::begin(persons), std::end(persons), pred);
    if( itr!= std::end(persons))
    {
        cout << "Search item found, person first-name: " << searchName << " has last name: " << itr->lastname <<'\n';
    }
    else
    {
        cout << "Search item not found \n";
    }
}
void sortperson(vector<Person> persons)
{
    sort( persons.begin( ), persons.end( ), [ ]( const Person& lhs, const Person& rhs )
    {
        if(lhs.lastname != rhs.lastname)
        {
            return lhs.lastname < rhs.lastname;
        }
        else
        {
            return lhs.firstname < rhs.firstname;
        }

    });


    for(auto& e : persons)
    {
        cout << right << setw(20) << e.firstname;
        cout << setw(20) << e.lastname;
       // cout << right << setw(5) << e.length << endl;
    }
}

bool yesOrNo(string str)
{
    cout << str;
    char ch;
    do
    {
        cin >> ch;
        cin.get();
        ch=toupper(ch);
    }while(!(ch=='Y'||ch=='N'));
    return (ch=='Y');
};


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
struct person
{
    std::string firstname;
    std::string lastname;
    float length;
};

// sort based on the last name (if the last name matches sort on first name)
void sort( std::vector<person>& persons )
{
    // make a pair of names with first == lastname, second == firstname
    static const auto name_pair = [] ( const person& p ) { return std::make_pair( p.lastname, p.firstname ); };

    // compare last name; if last names are equal, then compare first name
    // http://en.cppreference.com/w/cpp/utility/pair/operator_cmp
    static const auto cmp = [] ( const person& a, const person& b ) { return name_pair(a) < name_pair(b) ; } ;

    std::sort( std::begin(persons), std::end(persons), cmp ) ;
}

http://coliru.stacked-crooked.com/a/77845dc892d252a0
Thanks for all the answers, really appreciate it!
To make it sort regardless if the letters are uppercase or lowercase do I need to convert the string to either lower- or uppercase and then sort it?
Convert the strings to either lower or uppercase and then compare them.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// case-insensitive sort based on the last name (if the last name matches sort on first name)
void sort( std::vector<person>& persons )
{
    static const auto to_lower = [] ( std::string str ) // return all lower case string
    { for( char& c : str ) c = std::tolower(c) ; return str ; } ;

    // make a pair of names with first == lastname in lower case, second == firstname in lower case
    static const auto name_pair = [] ( const person& p )
    { return std::make_pair( to_lower(p.lastname), to_lower(p.firstname) ); };

    // compare last name; if last names are equal, then compare first name
    // http://en.cppreference.com/w/cpp/utility/pair/operator_cmp
    static const auto cmp = [] ( const person& a, const person& b ) { return name_pair(a) < name_pair(b) ; } ;

    std::sort( std::begin(persons), std::end(persons), cmp ) ;
}

http://coliru.stacked-crooked.com/a/6b1347cabd5bd915
Wouldn't just this work?

transform(persons.begin(), persons.end(), persons.begin(), ::tolower);
One simple way:
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
#include <iostream>
#include <iomanip>
#include <string>
#include <cstring>
#include <vector>
#include <algorithm>

using namespace std;

struct Person
{
  string firstname;
  string lastname;
  float length;
};

int main()
{
   vector<Person> people = 
  {
    { "Anna", "Smith", 2.2f},
    {"Jenna", "haglund", 1.4f},
    { "Anna", "Doe", 1.2f},
    { "Lisa", "miller", 3.2f},
    { "Molly", "Myer", 4.6f},
  };
 
  sort(people.begin(), people.end(), [](const Person& lhs, const Person& rhs)
  {
    return stricmp(lhs.lastname.c_str(), rhs.lastname.c_str()) < 0;
  });

  for (Person& p : people)
  {
    cout  << p.firstname << '\t' << p.lastname  << '\t' << p.length << '\n';
  }

  system("pause");
  return 0;
}


OUTPUT:

Anna Doe 1.2
Jenna haglund 1.4
Lisa miller 3.2
Molly Myer 4.6
Anna Smith 2.2
Press any key to continue . . .
Last edited on
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
47
48
49
50
51
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <cctype>
using namespace std;


string toUpper( const string s )
{
   string upper = s;
   for ( int i = 0; i < s.size(); i++ ) upper[i] = toupper( upper[i] );
   return upper;
}


struct Person
{
   string firstname;
   string lastname;
   float length;        // what?
   Person( string first, string last, float len ) : firstname( first ), lastname( last ), length( len ) {}
};


bool cmp( Person A, Person B )
{
   if ( toUpper( A.lastname ) == toUpper( B.lastname ) ) return ( toUpper( A.firstname ) < toUpper( B.firstname ) );
   else                                                  return ( toUpper( A.lastname  ) < toUpper( B.lastname  ) );
} 


ostream &operator<< ( ostream &stream, Person &p ) { stream << p.firstname << " " << p.lastname;   return stream; }



int main()
{

   vector<Person> people;
   people.push_back( Person( "David", "Small", 1.5 ) );
   people.push_back( Person( "David", "LARGE", 2.2 ) );
   people.push_back( Person( "Bob"  , "Small", 1.3 ) );
   people.push_back( Person( "Alice", "Large", 1.6 ) );
   people.push_back( Person( "ABC"  , "xyz"  , 1.7 ) );
   people.push_back( Person( "XYZ"  , "abc"  , 1.6 ) );

   sort( people.begin(), people.end(), cmp );

   for ( int i = 0; i < people.size(); i++ ) cout << people[i] << endl;
}
Last edited on
Topic archived. No new replies allowed.