# Iterators, Algorithms, Lambdas and Ranges — C++

Source: https://www.skillbyai.com/en/cpp/s-algorithms

> Use standard algorithms with lambdas and C++20 ranges instead of hand-written loops.

## Say what, not how

The `<algorithm>` and `<numeric>` headers provide well-tested generic algorithms: `std::sort`, `std::stable_sort`, `std::find`, `std::find_if`, `std::count_if`, `std::binary_search`, `std::lower_bound`, `std::transform`, `std::accumulate`, `std::remove_if`, `std::unique`, `std::max_element` and many more. Classic algorithms take a pair of **iterators** marking a half-open range `[begin, end)`. **Lambdas** (`[](int x) { return x > 50; }`) supply custom behaviour inline; the **capture list** controls access to surrounding variables by value (`[threshold]`) or reference (`[&total]`). **C++20 ranges** (`<ranges>`) let you pass whole containers (`std::ranges::sort(v)`) and compose lazy **views** with the pipe operator: `v | std::views::filter(pred) | std::views::transform(f)`. Algorithms express intent clearly, avoid off-by-one errors and are often optimised. Note the **erase-remove idiom** for vectors before C++20 (`v.erase(std::remove_if(...), v.end())`), replaced in C++20 by **`std::erase_if(v, pred)`**.

## Algorithms and ranges instead of loops

Each line replaces a hand-written loop.

```cpp
#include <algorithm>
#include <numeric>
#include <ranges>
#include <string>
#include <vector>

struct Student { std::string name; int marks; };

int main() {
    std::vector<Student> cls{{"Asha", 91}, {"Ravi", 64}, {"Meera", 78}, {"Kabir", 38}};

    std::ranges::sort(cls, std::ranges::greater{}, &Student::marks);    // by marks, descending

    int threshold = 60;
    auto passed = std::ranges::count_if(cls, [threshold](const Student& s) { return s.marks >= threshold; });

    double avg = std::accumulate(cls.begin(), cls.end(), 0.0,
        [](double sum, const Student& s) { return sum + s.marks; }) / cls.size();

    auto top_names = cls
        | std::views::filter([](const Student& s) { return s.marks >= 75; })
        | std::views::transform(&Student::name);                         // lazy view
    for (const auto& n : top_names) { /* Asha, Meera */ }

    std::erase_if(cls, [](const Student& s) { return s.marks < 40; });   // C++20

    std::vector<int> sorted{3, 8, 15, 21, 40};
    bool has15 = std::ranges::binary_search(sorted, 15);                  // O(log n)
}
```

## Kitchen appliances

Writing every loop by hand is chopping everything with a knife. Standard algorithms are a well-tested food processor with labelled settings: sort, filter, count. You still choose the recipe (the lambda).

**Quiz:** What does the capture list `[&total]` in a lambda mean?

- [ ] The lambda receives total as a parameter
- [ ] The lambda copies total
- [ ] total becomes a global variable
- [x] The lambda captures total by reference, so changes affect the original variable

*Answer:* The lambda captures total by reference, so changes affect the original variable. & captures by reference; without & the variable would be copied into the lambda.
