Custom comparators with lambda for sort/PQ

RoadmapsC++

Scenario

You have a `std::vector<Player>` where `Player` is a struct containing a name and a score. You call `std::sort(players.begin(), players.end())`. The compiler outputs 200 lines of incomprehensible template error garbage.

How do you teach `std::sort` how to compare two custom objects?

Mental model

A Lambda is a disposable, nameless function you write directly inline. A custom comparator is like handing the sorting robot a rulebook: 'When looking at A and B, return true if A should strictly be placed before B.'

STL algorithms and containers rely on the `<` operator by default to sort elements. If your object doesn't have an `operator<`, or if you want to sort by a different rule (e.g., descending order, or sorting by string length), you must provide a Custom Comparator. In modern C++, this is almost exclusively done using Lambda Expressions.

Explanation

**Lambda Basics:**

A lambda expression is an anonymous function defined inline.

Syntax: `[captures] (parameters) { body }`

- **[ ]** (Capture clause): Defines what outside variables the lambda can access.

- **( )** (Parameters): The inputs to the lambda.

- **{ }** (Body): The logic.

**Customizing std::sort:**

`std::sort` takes a 3rd argument: a callable object that takes two arguments (A and B) and returns `true` if A should be placed **strictly before** B.

For example, to sort descending: `std::sort(v.begin(), v.end(), [](int a, int b) { return a > b; });`

To handle tie-breakers (multi-level sorting), you simply add conditional logic: `if (a.score != b.score) return a.score > b.score; return a.name < b.name;`.

**Customizing std::priority_queue:**

Priority Queues are trickier because the comparator is part of the *type signature*. By default, it's a Max-Heap (uses `std::less`). To make a Min-Heap (smallest at top), you use the built-in `std::greater`. If you need a custom struct PQ, you typically pass a `decltype` of your lambda as the template argument, and pass the lambda itself into the constructor.

**Real-world Engineering:**

Lambdas revolutionized C++. They replaced writing dozens of one-off, polluting structs just to satisfy a sorting requirement. You will use lambdas constantly when filtering vectors (`std::erase_if`), sorting API responses by various JSON fields, or configuring priority queues for A* pathfinding.

Code examples

Sorting with Lambdas

#include <vector>
#include <algorithm>
#include <string>

struct Player {
    std::string name;
    int score;
};

int main() {
    std::vector<Player> players = {{"Alice", 50}, {"Bob", 90}, {"Charlie", 10}};
    
    // Sort descending by score using a lambda.
    // Returns true if 'a' should come BEFORE 'b'.
    std::sort(players.begin(), players.end(), [](const Player& a, const Player& b) {
        return a.score > b.score; 
    });
    
    // players is now: Bob (90), Alice (50), Charlie (10)
    return 0;
}

Passing `const Player&` avoids expensive copies. Returning `a.score > b.score` tells the sort algorithm to put higher scores first.

Min-Heap Priority Queue

#include <queue>
#include <vector>

int main() {
    // Standard PQ is a Max-Heap.
    // To make a Min-Heap, we must specify the container (vector)
    // and provide the std::greater comparator.
    std::priority_queue<int, std::vector<int>, std::greater<int>> minHeap;
    
    minHeap.push(10);
    minHeap.push(2);
    minHeap.push(50);
    
    // Top is now 2, not 50.
    
    return 0;
}

`std::greater` is a built-in functor that reverses the default `<` comparison, turning the Max-Heap into a Min-Heap.

Key points

Common mistakes

Recall questions

Questions & answers

An interviewer asks you to sort an array of strings by their length (shortest to longest). How do you do this using `std::sort`?

You provide a lambda comparator: `std::sort(vec.begin(), vec.end(), [](const string& a, const string& b) { return a.length() < b.length(); });`

Approach: Apply lambdas to override default sorting behavior (which would sort strings alphabetically).

A team member wants to sort a vector of `std::pair<int, int>` such that the first elements are ascending, but if they are equal, the second elements are descending. How would you write the lambda?

```cpp [](const std::pair<int, int>& a, const std::pair<int, int>& b) { if (a.first != b.first) return a.first < b.first; return a.second > b.second; } ``` This handles the primary and secondary sort conditions while maintaining strict weak ordering.

Approach: Demonstrate how to write multi-level sorting logic in a lambda.

Continue learning

Previous: sort, binary_search, lower_bound & upper_bound

Return to C++ Roadmap