Sorting Multiple Vectors

Please support our C++ advertiser: Intel Parallel Studio Home
Reply

Join Date: Apr 2008
Posts: 8
Reputation: xtheendx is an unknown quantity at this point 
Solved Threads: 0
xtheendx xtheendx is offline Offline
Newbie Poster

Sorting Multiple Vectors

 
0
  #1
May 2nd, 2008
In my program i have three sperate vectors that store the students last name, first and score. I need to sort it by last name and print the contents of the vectors lastname, firstname: score. Well i have got it doing that for the most part. But after it sorts the lastnames the first names and scores are still in the same postion in their vectors, so when it prints the reults the last names are with the wrong first name and score. any ideas?

  1. #include <iostream> // allows the program to output data to the screen
  2. #include <conio.h>
  3. #include <iomanip>
  4. #include <cstdlib>
  5. #include <string>
  6. #include <vector>
  7. #include <algorithm>
  8. #include <numeric>
  9. #include <fstream>
  10. #include <ios>
  11. #include <istream>
  12. #include <limits>
  13. #include "students.h" // gradebook class defintion
  14.  
  15.  
  16. using std::cout; // program uses cout
  17. using std::cin; // program uses cin
  18. using std::endl; // program uses endl
  19. using std::setprecision; // set numeric output precision
  20. using std::fixed; // ensures that decimal point is displayed
  21. using std::setw;
  22. using std::string;
  23. using std::vector;
  24. using std::max;
  25.  
  26.  
  27. void students::displayMessage()
  28. {
  29.  
  30. cout << endl << "Welcome to the Student Scores Application." << endl << endl;
  31. }
  32.  
  33.  
  34. void students::getData()
  35. {
  36. int numStudents = 0;
  37. string name;
  38. int score = 0;
  39. int i = 0;
  40.  
  41. cout <<"Enter number of students to enter: ";
  42. cin >> numStudents;
  43. cin.ignore ( std::numeric_limits<std::streamsize>::max(), '\n' );
  44.  
  45. vector<string> student_lastnames;
  46. vector<string> student_firstnames;
  47. vector <int> student_score;
  48.  
  49. do
  50.  
  51. {
  52. cout << endl << "Student " << i + 1 <<" last name: ";
  53. cin >> name;
  54. cin.ignore ( std::numeric_limits<std::streamsize>::max(), '\n' );
  55. student_lastnames.push_back(name);
  56.  
  57.  
  58.  
  59.  
  60. cout << "Student " << i + 1 <<" first name: ";
  61. cin >> name;
  62. cin.ignore ( std::numeric_limits<std::streamsize>::max(), '\n' );
  63. student_firstnames.push_back(name);
  64.  
  65. cout << "Student " << i + 1 <<" score: ";
  66. cin >> score;
  67. cout << endl;
  68. cin.ignore ( std::numeric_limits<std::streamsize>::max(), '\n' );
  69. student_score.push_back(score);
  70.  
  71. i++;
  72. }
  73.  
  74. while ( i < numStudents);
  75.  
  76.  
  77. // sort them alphabetically
  78. sort (student_lastnames.begin(), student_lastnames.end());
  79.  
  80. for (int i =0; i < student_lastnames.size(); i++)
  81. {
  82. cout << student_lastnames[i] << ", " << student_firstnames[i] << ": " << student_score[i] << endl;
  83. }
  84.  
  85.  
  86.  
  87. }
  88.  
  89. void students::End()
  90. {
  91. cout << endl << endl << "Press any key to continue..."; // prompts the user to continue or quit
  92. char c = getch();
  93. }
  94.  
  95.  
  96. // function main begins program exectuion
  97. int main()
  98. {
  99. students mystudent;
  100.  
  101. mystudent.displayMessage();
  102.  
  103. mystudent.getData();
  104.  
  105. mystudent.End();
  106.  
  107. }
Reply With Quote Quick reply to this message  
Join Date: Apr 2006
Posts: 5,051
Reputation: John A is a splendid one to behold John A is a splendid one to behold John A is a splendid one to behold John A is a splendid one to behold John A is a splendid one to behold John A is a splendid one to behold John A is a splendid one to behold John A is a splendid one to behold 
Solved Threads: 332
Team Colleague
John A's Avatar
John A John A is offline Offline
Vampirical Lurker

Re: Sorting Multiple Vectors

 
1
  #2
May 2nd, 2008
Make a class that contains the firstname, lastname, and score. Now overload the '<' operator for it so that returns the object which is 'smaller' in terms of lastname. Finally, run std::sort on the entire vector, which will in turn use your overloaded operator< for your class.
"Technological progress is like an axe in the hands of a pathological criminal."

All my posts may be freely redistributed under the terms of the MIT license.
Reply With Quote Quick reply to this message  
Join Date: May 2008
Posts: 351
Reputation: Radical Edward has a spectacular aura about Radical Edward has a spectacular aura about Radical Edward has a spectacular aura about 
Solved Threads: 62
Radical Edward's Avatar
Radical Edward Radical Edward is offline Offline
Posting Whiz

Re: Sorting Multiple Vectors

 
1
  #3
May 2nd, 2008
You should abstract your data into objects so that it's easier to make changes and the design is clearer. Right now you have three vectors of data that should be encapsulated in a student class:
  1. class Student {
  2. std::string _firstName;
  3. std::string _lastName;
  4. int _score;
  5.  
  6. friend std::ostream& operator<<(std::ostream& os, const Student& rhs);
  7. friend std::istream& operator>>(std::istream& is, const Student& rhs);
  8. public:
  9. Student(const std::string& firstName = "",
  10. const std::string& lastName = "",
  11. const Score& score = Score())
  12. : _firstName(firstName), _lastName(lastName), _score(score) {}
  13. };
That covers I/O and all of the basic object stuff. If you want to sort students you need to be able to compare the key data, but Edward will get to that in a moment. First, Ed doesn't like the use of int for a score. It's easy to see changes there, so it's a good idea to abstract the score away into its own object:
  1. class Score {
  2. int _score;
  3.  
  4. friend std::ostream& operator<<(std::ostream& os, const Score& rhs);
  5. friend std::istream& operator>>(std::istream& is, Score& rhs);
  6. friend bool operator<(const Score& lhs, const Score& rhs);
  7. public:
  8. Score(int score = 0): _score(score) {}
  9. };
  10.  
  11. std::ostream& operator<<(std::ostream& os, const Score& rhs)
  12. {
  13. return os << rhs._score;
  14. }
  15.  
  16. std::istream& operator>>(std::istream& is, Score& rhs)
  17. {
  18. return is >> rhs._score;
  19. }
  20.  
  21. bool operator<(const Score& lhs, const Score& rhs)
  22. {
  23. return lhs._score < rhs._score;
  24. }
The << and >> operators are there to support the same operators from the student class, and the < operator is for sorting. A > operator isn't needed because the < operator can be combined with STL function objects to reverse the test. Edward will show you how that's done shortly. With the score class, you can change what the underlying type is without monkeying in the rest of the code.

If you tried that code, you may notice that it doesn't support sorting yet. While John A's suggestion of using an overloaded < operator is good for general sorting, it doesn't take into account that you might want to sort on different keys. For example, you could sort based on the score to get an overview of how the students did. But then you could also want to sort based on the student's names--first or last--to more easily cross reference with conventional reports.

With that in mind, Edward recommends using binary predicates and selecting them from the call to the sort algorithm. That way you don't lock yourself into sorting on only a single key:
  1. #include <algorithm>
  2. #include <functional>
  3. #include <iostream>
  4. #include <ostream>
  5. #include <string>
  6. #include <vector>
  7.  
  8. namespace StudentScores {
  9. //
  10. // Holds and manages score data
  11. //
  12. class Score {
  13. int _score;
  14.  
  15. // Provide support for I/O through insertion and extraction operators
  16. friend std::ostream& operator<<(std::ostream& os, const Score& rhs);
  17. friend std::istream& operator>>(std::istream& is, Score& rhs);
  18.  
  19. // Provide support for basic comparison
  20. friend bool operator<(const Score& lhs, const Score& rhs);
  21. public:
  22. Score(int score = 0): _score(score) {}
  23. };
  24.  
  25. std::ostream& operator<<(std::ostream& os, const Score& rhs)
  26. {
  27. return os << rhs._score;
  28. }
  29.  
  30. std::istream& operator>>(std::istream& is, Score& rhs)
  31. {
  32. return is >> rhs._score;
  33. }
  34.  
  35. bool operator<(const Score& lhs, const Score& rhs)
  36. {
  37. return lhs._score < rhs._score;
  38. }
  39.  
  40. //
  41. // Holds and manages student scoring information
  42. //
  43. class Student {
  44. std::string _firstName;
  45. std::string _lastName;
  46. Score _score;
  47.  
  48. // Provide support for I/O through insertion and extraction operators
  49. friend std::ostream& operator<<(std::ostream& os, const Student& rhs);
  50. friend std::istream& operator>>(std::istream& is, Student& rhs);
  51.  
  52. // Provide support for binary predicate comparison on each key
  53. friend class OrderByFirstName;
  54. friend class OrderByLastName;
  55. friend class OrderByScore;
  56. public:
  57. Student(const std::string& firstName = "",
  58. const std::string& lastName = "",
  59. const Score& score = Score())
  60. : _firstName(firstName), _lastName(lastName), _score(score) {}
  61. };
  62.  
  63. std::ostream& operator<<(std::ostream& os, const Student& rhs)
  64. {
  65. // Force a "lastname, firstname -- score" format
  66. return os << rhs._lastName << ", " << rhs._firstName << " -- " << rhs._score;
  67. }
  68.  
  69. std::istream& operator>>(std::istream& is, Student& rhs)
  70. {
  71. // Info: Input format is different from output, might want to change
  72. return is >> rhs._firstName >> rhs._lastName >> rhs._score;
  73. }
  74.  
  75. //
  76. // Binary predicates for Student comparison
  77. //
  78. class OrderByFirstName: public std::binary_function<Student, Student, bool> {
  79. public:
  80. bool operator()(const Student& lhs, const Student& rhs) const
  81. {
  82. return lhs._firstName < rhs._firstName;
  83. }
  84. };
  85.  
  86. class OrderByLastName: public std::binary_function<Student, Student, bool> {
  87. public:
  88. bool operator()(const Student& lhs, const Student& rhs) const
  89. {
  90. return lhs._lastName < rhs._lastName;
  91. }
  92. };
  93.  
  94. class OrderByScore: public std::binary_function<Student, Student, bool> {
  95. public:
  96. bool operator()(const Student& lhs, const Student& rhs) const
  97. {
  98. return lhs._score < rhs._score;
  99. }
  100. };
  101. }
  102.  
  103. void Display(const std::vector<StudentScores::Student>& students);
  104. void DisplaySortedByFirstName(std::vector<StudentScores::Student>& students);
  105. void DisplaySortedByLastName(std::vector<StudentScores::Student>& students);
  106. void DisplaySortedByScore(std::vector<StudentScores::Student>& students);
  107.  
  108. int main()
  109. {
  110. using StudentScores::Student;
  111.  
  112. std::vector<Student> students;
  113.  
  114. // Load students into the vector until EOF or a stream error
  115. while (std::cin) {
  116. Student input;
  117.  
  118. std::cout << "Enter a student (first last score): ";
  119.  
  120. if (!(std::cin >> input))
  121. break;
  122.  
  123. students.push_back(input);
  124. }
  125.  
  126. // Display the list sorted by the available keys
  127. DisplaySortedByFirstName(students);
  128. DisplaySortedByLastName(students);
  129. DisplaySortedByScore(students);
  130. }
  131.  
  132. void Display(const std::vector<StudentScores::Student>& students)
  133. {
  134. using StudentScores::Student;
  135.  
  136. std::vector<Student>::const_iterator i = students.begin();
  137.  
  138. while (i != students.end()) {
  139. std::cout << *i << '\n';
  140. ++i;
  141. }
  142.  
  143. std::cout << '\n';
  144. }
  145.  
  146. void DisplaySortedByFirstName(std::vector<StudentScores::Student>& students)
  147. {
  148. using StudentScores::Student;
  149. using StudentScores::OrderByFirstName;
  150.  
  151. // Create a new vector to sort so the original remains unchanged
  152. std::vector<Student> sorted = students;
  153. std::sort(students.begin(), students.end(), OrderByFirstName());
  154. Display(students);
  155. }
  156.  
  157. void DisplaySortedByLastName(std::vector<StudentScores::Student>& students)
  158. {
  159. using StudentScores::Student;
  160. using StudentScores::OrderByLastName;
  161.  
  162. // Create a new vector to sort so the original remains unchanged
  163. std::vector<Student> sorted = students;
  164. std::sort(students.begin(), students.end(), OrderByLastName());
  165. Display(students);
  166. }
  167.  
  168. void DisplaySortedByScore(std::vector<StudentScores::Student>& students)
  169. {
  170. using StudentScores::Student;
  171. using StudentScores::OrderByScore;
  172.  
  173. // Create a new vector to sort so the original remains unchanged
  174. std::vector<Student> sorted = students;
  175. std::sort(students.begin(), students.end(), OrderByScore());
  176. Display(students);
  177. }
The predicate function objects--classes with the name pattern OrderBy*--derive from std::binary_function<Student, Student, bool> because that base is needed to support the STL function objects you might want to use to sort descending rather than ascending. To do that you can use not2 in the sort call:
  1. std::sort(students.begin(), students.end(), not2(OrderByFirstName()));
But not2 expects OrderByFirstName to have members called first_argument_type, second_argument_type, and result_type. You get those automatically by deriving from binary_function<first_argument_type, second_argument_type, result_type> .

That's all there is to it, and Ed likes the flexibility of this design. I know it's probably too much right now, but you should always push your limits!
If at first you don't succeed, keep on sucking until you do succeed.
Reply With Quote Quick reply to this message  
Join Date: Dec 2006
Posts: 1,089
Reputation: vijayan121 is a name known to all vijayan121 is a name known to all vijayan121 is a name known to all vijayan121 is a name known to all vijayan121 is a name known to all vijayan121 is a name known to all 
Solved Threads: 164
vijayan121 vijayan121 is offline Offline
Veteran Poster

Re: Sorting Multiple Vectors

 
0
  #4
May 2nd, 2008
another way is to use a "tag sort". ie. create an index into the vectors and then sort the indices, rather than the three vectors.
note: this is usually done for efficiency reasons (swap a pair of integers instead of swap three pairs of strings).
  1. // ...
  2. std::vector<std::string> lastnames;
  3. std::vector<std::string> firstnames;
  4. std::vector<int> score;
  5. std::vector<std::size_t> tags ;
  6.  
  7. // fill up lastnames, firstnames, score
  8.  
  9. for( size_t i=0 ; i<lastnames.size() ; ++i ) tags.push_back(i) ;
  10.  
  11. // sort indices (tags)
  12. for( size_t i=0 ; i<tags.size() ; ++i )
  13. for( size_t j=i+1 ; j<tags.size() ; ++j )
  14. if( lastnames[j] < lastnames[i] )
  15. std::swap( tags[j], tags[i] ) ;
  16.  
  17. // print in sorted tag order
  18. for( size_t i=0 ; i<tags.size() ; ++i )
  19. {
  20. std::size_t pos = tags[i] ;
  21. std::cout << lastnames[pos] << ", " << firstnames[pos]
  22. << ": " << score[pos] << '\n' ;
  23. }
  24. // ...

> you might want to use to sort descending rather than ascending.
> To do that you can use not2 in the sort call:
> std::sort(students.begin(), students.end(), not2(OrderByFirstName()));
not really. std::sort requires the binary predicate used for comparisons to define a "strict weak ordering". http://www.sgi.com/tech/stl/StrictWeakOrdering.html
>= is neither irreflexive nor antisymmetric.
Reply With Quote Quick reply to this message  
Join Date: Dec 2006
Posts: 1,089
Reputation: vijayan121 is a name known to all vijayan121 is a name known to all vijayan121 is a name known to all vijayan121 is a name known to all vijayan121 is a name known to all vijayan121 is a name known to all 
Solved Threads: 164
vijayan121 vijayan121 is offline Offline
Veteran Poster

Re: Sorting Multiple Vectors

 
0
  #5
May 2nd, 2008
stupid error in earlier code, corrected here:
  // sort indices (tags)
  for( size_t i=0 ; i<tags.size() ; ++i )
    for( size_t j=i+1 ; j<tags.size() ; ++j )
      if( lastnames[ tags[j] ] < lastnames[ tags[i] ] )
         std::swap( tags[j], tags[i] ) ;
Reply With Quote Quick reply to this message  
Join Date: Apr 2008
Posts: 8
Reputation: xtheendx is an unknown quantity at this point 
Solved Threads: 0
xtheendx xtheendx is offline Offline
Newbie Poster

Re: Sorting Multiple Vectors

 
0
  #6
May 2nd, 2008
hey man that worked wonders. I would ahve never thought of that because i have never heard of tags. but i defiantly learned somthing. thanks alot
Reply With Quote Quick reply to this message  
Reply

This thread is more than three months old.
Perhaps start a new thread instead?
Message:


Thread Tools Search this Thread



About Us | Contact Us | Advertise | DaniWeb | Acceptable Use Policy | RSS Feed

©2003 - 2009 DaniWeb® LLC