1

I am trying to sort students name and their marks. I want to sort mark first then sort string of student names with same marks.

Here is my code so far:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main()
{
    struct student
    {
        int mark;
        string name;
       
    };

    vector <student> s = {
    {30, "Mark"},
    {14, "Mitch"},
    {23, "Hen"},
    {30, "Abo"}
    };

    sort(s.begin(), s.end(), [](const student& a, const student& b) { return (a.mark < b.mark); });

    for (const auto& x : s)
        cout << x.mark << ", " << x.name << endl;
}

This code outputs as expected (sorts marks):

14, Mitch
23, Hen
30, Mark
30, Abo

However, I also want it to sort name of students with same grades, i.e. Mark and Abo have same marks of 30, therefore Abo should come before Mark (due to the alphabetical order of their names).

Expected output:

14, Mitch
23, Hen
30, Abo
30, Mark
Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
KarateKing
  • 35
  • 4
  • Hint: that comparator lambda is going to get a bit more.. [involved](https://stackoverflow.com/a/328959/1322972). – WhozCraig Apr 18 '21 at 13:07

3 Answers3

5

You could use std::tie:

std::sort(s.begin(), s.end(), [](const student& a, const student& b) 
         { return std::tie(a.mark, a.name) < std::tie(b.mark, b.name); });

Using std::tie makes it a little easier to write comparators that "cascade" from one entry to the next when there is (no pun intended) a "tie" in one of the entries.

PaulMcKenzie
  • 34,698
  • 4
  • 24
  • 45
1

You should use a comparision function that matches your specification.

sort(s.begin(), s.end(),
    [](const student& a, const student& b) {
        return
            a.mark < b.mark // a < b if a.mark is less than b.mark
            ||
            (a.mark == b.mark && // when a.mark equals to b.mark
             a.name < b.name);   // compare their name
    }
);
MikeCAT
  • 73,922
  • 11
  • 45
  • 70
  • hey @MikeCAT thank you for the answer, I just split the class into .h file and i get this error Error C2664 'bool main: ::operator ()(const Student &,const Student &) const': cannot convert argument 1 from 'Student *' to 'const Student &' Any idea on why i am getting this? – KarateKing Apr 18 '21 at 14:27
  • It looks like bcause you are passing `Student*` where `Student` is expected. – MikeCAT Apr 18 '21 at 14:29
  • Hey @MikeCAT thank you for quick reply, the error went away but another error appeared, Error C2440 'initializing': cannot convert from 'student' to 'student', any idea why? thank you for your time. Appreciate it – KarateKing Apr 18 '21 at 14:39
1

You can use the ternary operator to check if the marks are equal and, if so, compare the names; otherwise just compare the marks:

sort(s.begin(), s.end(), [](const student& a, const student& b) {
    return (a.mark == b.mark) ? (a.name < b.name) : (a.mark < b.mark); }
);
Adrian Mole
  • 49,934
  • 160
  • 51
  • 83