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.