Home > database >  Implement C sort function, according to the input items to sort
Implement C sort function, according to the input items to sort

Time:03-10

I create an array of a struct:

struct student {
    char name[20];
    int num1;
    int num2;
} temp[20] = {0};

Its internal data is like this:

temp[0]={'a',1,11};
temp[1]={'b',2,12};
temp[2]={'c',3,13};
temp[3]={'d',4,14};
temp[4]={'e',5,15};
...

I know that I can define a compare function to tell the sort() function the role of sorting, for example:

bool cmp (student a,student b){
    return a.num1 > b.num1;
}

sort(temp, temp 20, cmp);

My question is: How could I sort the array using this sort() function based on the items I read in with scanf()?

Specifically, if I scanf() the num1 field, the sort function sorts the data based on num1.

If I scanf() the num2 field, the sort function sorts the data based on num2.

The role of sorting follows my scanf() item.

So, how can I realize this?

CodePudding user response:

You can have both the reading and the sorting depend on a pointer-to-member.

So instead of

void read_num1(student & s) {
    std::scanf("%d", std::addressof(s.num1));
}

void compare_num1(student lhs, student rhs) {
    return lhs.num1 < rhs.num1;
}

int main() {
    student students[20];
    for (student & s : students) {
        read_num1(s);
    }

    std::sort(std::begin(students), std::end(students), compare_num1);
}

You have functions that have an extra parameter, and close over that where necessary

using member_t = int (student::*);

void read(student & s, member_t member) {
    std::scanf("%d", std::addressof(s.*member));
}

void compare(student lhs, student rhs, member_t member) {
    return (lhs.*member) < (rhs.*member);
}

int main() {
    member_t member = /* some condition */ true ? &student::num1 : &student::num2;

    student students[20];
    for (student & s : students) {
        read(s, member);
    }

    std::sort(std::begin(students), std::end(students), [member](student lhs, student rhs) { return compare(lhs, rhs, member); });
}

CodePudding user response:

I recommend using the ranges interface for sort in the STL. Change your array to use std::array or better std::vector and then you can do sorting as simple as this:

ranges::sort(s, [](int a, int b) { return a > b; });
print("Sort using a lambda expression", s);

Particle particles[] {
    {"Electron", 0.511}, {"Muon", 105.66}, {"Tau", 1776.86},
    {"Positron", 0.511}, {"Proton", 938.27}, {"Neutron", 939.57},
};
ranges::sort(particles, {}, &Particle::name);
print("\nSort by name using a projection", particles, '\n');
ranges::sort(particles, {}, &Particle::mass);
print("Sort by mass using a projection", particles, '\n');

And if you want to sort by multiple fields, e.g last_name, first_name, you can use a std::tuple with references into your struct as projection. std::tuple has lexicographical comparison so you really just have to give the order of fields and the rest happens by magic.

  •  Tags:  
  • c
  • Related