2

I'm the headmaster of a very large public school and I've been watching my kids growing up for ten years. Their basic info and test scores each year are stored as follows:

class KidInfo{
    string name;
    int age;
    vector<int> score; //The lengths increases as my kids grows up
};

const int NUM = 100000;  //Wow, that's gigantic my friend

KidInfo myKids[NUM];

Now I want to analyze these results and create their study profile. To do this I need to sort the array myKids by their test scores in descending order each year, for ten years. I have to use std::sort to guarentee efficincy since I'm running quite a large school.

I'm not a very skillful C++ programmer and have no idea how to handle this task. After checking the answer sort multidimensional vector by 1st column, I wrote the following code:

bool cmpByYear1(const KidInfo &k1, const KidInfo &k2){
    return k1.score[0] > k2.score[0];
}

bool cmpByYear2(const KidInfo &k1, const KidInfo &k2){
    return k1.score[1] > k2.score[1];
}

//And 8 similiar functions

sort(muKids, myKids + NUM, cmpByYear1);
//print Year 1...
sort(muKids, myKids + NUM, cmpByYear2);
//print Year 2, and so on...

It didn't take too long before I got bored writing a new cmpByYearN function each year, so I'm thinking about more elegant approaches, like template:

template<int year>
bool cmpAnyYear(const KidInfo &k1, const KidInfo &k2){
    return k1.score[year - 1] > k2.score[year - 1];
}

int main(){
    //...
    for(int year = 1; year <= 10; ++year){
        sort(myKids, myKids + NUM, cmpAnyYear<year>);
    }
    //...
    return 0;
}

Unfortunately my code got compile error with messages like “template parameter "year": local variables cannot be used as non-type parameter...”.

So I was thinking using a global parameter instead:

int globalYear = 1;

bool cmpAnyYear(const KidInfo &k1, const KidInfo &k2){
    return k1.score[globalYear - 1] > k2.score[globalYear - 1];
}

int main(){
    //...
    for(; globalYear <= 10; ++globalYear){
        sort(myKids, myKids + NUM, cmpAnyYear);
    }
    //...
    return 0;
}

This time my code actually runs, but sadly it still doesn't work: It looks like the cmpAnyYear function was already fixed when I declared globalYear = 1; and behaved just like cmpByYear1 regardless of the subsequent changes of globalYear. The sorting results remain unchanged from year 2.

2 Answers 2

2

You can use functor objects, like e.g.

struct cmpAnyYear
{
    cmpAnyYear(int year)
        : year_(year)
    {}

    bool operator()(KindInfo const& k1, KidInfo const& k2) const
    {
        return k1.score[year_ - 1] > k2.score[year_ - 1];
    }

    int year_;
}

int main(){
    //...
    for(int year = 1; year <= 10; ++year){
        sort(myKids, myKids + NUM, cmpAnyYear(year));
    }
    //...
    return 0;
}

The expression cmpAnyYear(year) constructs a (temporary) object of the type cmpAnyYear and passes year as argument to the constructor. This object is the "called" as a function, which calls the cmpAnyYear::operator() for the comparison.

Sign up to request clarification or add additional context in comments.

Comments

1

Use a lambda which captures the year:

int main()
{
    //...
    for (int year = 1; year <= 10; ++year) {
        sort(myKids, myKids + NUM, [year](const KidInfo& k1, const KidInfo& k2) {
            return k1.score[year - 1] > k2.score[year - 1];
        });
    }
    //...
    return 0;
}

The reason why year as template parameter didn't work is because it has to be a compile-time constant when you call it, which is not in your for loop.

3 Comments

Thanks, but still not quite understand why lambda would work, it still takes the local variable year as argument, huh? Does "compile-time" constant mean that the value of the argument should be fixed when the comparing function is created, and that lambda function should becreated just inside sort, and destructed before year is changed? Hope you could clarify it for me
@Lotayou You might want to read more about lambda expressions. Basically it create a temporary object of a temporary compiler-generated class, and works very much similar to my solution.
explaining lambdas is outside the scope of this question (and site). There are great resources on the net for explaining and introducing lambdas. As Joachim said, it is more or less a shorthand for his solution.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.