# Sorting

• How does a container like `set` know the sorting order?
• Sure, it’s easy to answer for `int` and `string`, but what about `class Student`?
• Sort by major?
• Sort by eId?
• Sort by last name, then first name, then CSUID?
• Besides, even for `int`, you might want to sort in a different order.
• You might even want multi-key sorting, like a phone book.

# The Idiot Savant

• Imagine that you had a semi-brilliant assistant who was very good at sorting.
• However, your assistant doesn’t know alphabetical order.
• He can do everything that’s needed for sorting except actually determine if, say, “Jay” comes before “David”.
• Therefore, he frequently comes to you, asking if this word comes before this other word.
• `set` is like that. It knows the mechanics of sorting, but it doesn’t know what order to use. You need to help it.

# Comparison functor

• You provide `set` with a comparison functor.
• The `set` code makes comparisons using the functor.
• The functor only compares two items at a time.
• I say again, two items at a time. Only two.
• The functor returns `true` iff the first item should come before the second item.
• Why can’t you use a comparison function, as opposed to a comparison functor?

# Implicit/explicit

Implicit sorting criterion:

```set<int> s = {31, 41, 59, 26, 53, 58, 97, 93, 23, 84};
for (auto v : s)
cout << v << ' ';
```
`23 26 31 41 53 58 59 84 93 97 `

Explicit sorting criterion:

```set<int, less<int> > s = {31, 41, 59, 26, 53, 58, 97, 93, 23, 84};
for (auto v : s)
cout << v << ' ';
```
`23 26 31 41 53 58 59 84 93 97 `

What’s this `> >` folderol?

# Reversed

Use `greater<int>` to sort from biggest to smallest:

```set<int, greater<int>> s = {31, 41, 59, 26, 53, 58, 97, 93, 23, 84};
for (auto v : s)
cout << v << ' ';
```
`97 93 84 59 58 53 41 31 26 23 `

# Explicitly explicit

Use a comparison functor that behaves the same as `less<int>`:

```struct compare {                            // 😱😱struct‽😱😱
bool operator()(int a, int b) const {
return a < b;
}
};

set<int, compare> s = {31, 41, 59, 26, 53, 58, 97, 93, 23, 84};
for (auto v : s)
cout << v << ' ';
```
`23 26 31 41 53 58 59 84 93 97 `

# Two-level

Use a comparison functor that does a two-level comparison, like last name/first name.

```struct compare {
bool operator()(int a, int b) const {
int da = abs(a-50), db = abs(b-50);
if (da != db)
return da < db; // Primary sort: distance from 50
return a < b;       // Secondary sort: value of number
}
};

set<int, compare> s = {31, 41, 59, 26, 53, 58, 97, 93, 23, 84};
for (auto v : s)
cout << v << ' ';
```
`53 58 41 59 31 26 23 84 93 97 `

# Ternary operator

Another way to write a two-level comparison functor:

```struct compare {
bool operator()(int a, int b) const {
int da = abs(a-50), db = abs(b-50);
return (da != db) ? da < db : a < b;
}
};

set<int, compare> s = {31, 41, 59, 26, 53, 58, 97, 93, 23, 84};
for (auto v : s)
cout << v << ' ';
```
`53 58 41 59 31 26 23 84 93 97 `

# Curious criteria

This sorts by different criteria:

```struct compare {
bool operator()(int a, int b) const {
int last_a = a%10, last_b = b%10;
if (last_a != last_b)
return last_a < last_b; // Primary sort: by last digit
return a < b;               // Secondary sort: value of number
}
};

set<int, compare> s = {31, 41, 59, 26, 53, 58, 97, 93, 23, 84};
for (auto v : s)
cout << v << ' ';
```
`31 41 23 53 93 84 26 97 58 59 `

# Multi-level

```struct student {
int id; string name; float gpa;
};
struct compare {
bool operator()(const student &a, const student &b) const {
return (a.gpa != b.gpa) ? a.gpa > b.gpa : a.id < b.id;
}
};
set<student,compare> s = {
{81234567, "Jack Applin",      3.9},
{82828282, "Darrell Whitley",  0.5},
{84444444, "Homecoming Queen", 2.2},
{83333333, "Joe Kolledge",     2.2},
};
for (const auto &v : s)
cout << v.id << ' ' << v.gpa << ' ' << v.name << '\n';
```
```81234567 3.9 Jack Applin
83333333 2.2 Joe Kolledge
84444444 2.2 Homecoming Queen
82828282 0.5 Darrell Whitley
```

# Not all

• Of course, not all collections require a comparison functor.
• `vector`, `array`, and `list` just go in the order you specify, and so have no comparison functor.
• `unordered_set` needs only an equality comparison (and a hash functor), so its comparison functor defaults to `equal_to`, not `less`.

User: Guest

Check: HTML CSS
Edit History Source

Modified: 2018-04-24T16:56

Apply to CSU | Contact CSU | Disclaimer | Equal Opportunity
Colorado State University, Fort Collins, CO 80523 USA