简体   繁体   中英

Sort vector by multiple values

i have to sort a vector. The vector contains pointers to objects of class "student".

the rating metric looks like this:

  1. best finalgrade
  2. if same finalgrade, less attempts
  3. if same attempts, less id
  4. students with 0 attempts are worse than students with 2 attempts and finalgrade 5, sort students with 0 attempts by less id

student looks like this:

private:
std::string name_;
int id_;
int attempts_;  //max 2, if 0, exam not taken
int grade1_;
int grade2_;
int finalGrade_;  // grade 5 for failed exam but still better than 0 attempts in rating

my problem is that i dont know how to handle attempts. because best number of attempts is 1 and its better than 2 attempts. but 2 attempts are better than 0 in the rating.

i hope you understand my problem and can help me. thx :)

There is a function available in the STL, called std::sort Which can take a comparator function, (either a function pointer, or a function object).

The comparator function has to return a boolean that says whether the first element should appear strictly before the second element.

Here's what I came up with for the comparator:

struct compare_student {
    inline bool 
    operator() (Student *left, Student *right) const
    {
        if(left->attempts_ == 0 && right->attempts_ == 0)
            return left->id_ < right->id_;
        else if(left->attempts_ == 0)
            return false;
        else if(right->attempts_ == 0)
            return true;

        return 
            left->finalGrade_ <  right->finalGrade_ ||    // Compare final grade
            left->finalGrade_ == right->finalGrade_ && (  // If final grade same:
                left->attempts_ <  right->attempts_ ||    // Compare attempts
                left->attempts_ == right->attempts_ && (  // If attempts same:
                    left->id_ < right->id_                // Compare id's
                )
            );
    }
};

Obviously all your fields are private, so you will need to use their accessor methods rather than just accessing them directly, but here's how you use it:

vector<Student *> students {...};
std::sort(students.begin(), students.end(), compare_student{});

std::sort is not stable, this means if two elements are considered equal, then it is not necessarily the case that they will keep their relative order, which may be important to you. If it is, then there is also a function called std::stable_sort which does have such a guarantee, and is used in exactly the same way:

std::stable_sort(students.begin(), students.end(), compare_students{});

EDIT Notes on the implementation

  • compare_students is a class that has only one, public member, so rather than do this:

     class compare_student { public: ... }; 

    I shortened it to this:

     struct compare_student { ... }; 

    (the two are equivalent in C++, a struct is just a class with default public access.)

  • Then as to what inline bool operator() means.

    • inline is a hint to the compiler that this function can be inlined, that is to say, replace the call with the code itself.
    • bool is the return type of the function.
    • operator() is the name of the function, It is a special-case function that gets called when you treat an object like a function:

       Student *a, *b; compare_student comparator {}; comparator(a, b); // calls comparator::operator()(a, b) 

Sounds like the first line of your comparison function should be

if (left.attempts_ == 0)

From there, check whether right.attempts_ == 0 as well. If yes, check the IDs.

If no, then right has a grade and left doesn't, right is better.

Continue on with the rest of the rules. Eventually you can use rules like if (left.attempts_ < right.attempts_) but only after you've dealt with 0 attempts.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM