accumulate, transform & common <algorithm> patterns

RoadmapsC++

Scenario

You need to multiply every number in a vector by 2, and then sum them up. You write a standard `for` loop with a running total. A senior engineer comments on your PR: "This is imperative. Make it declarative using `<numeric>`."

What is the difference between "imperative" loops and "declarative" algorithms?

Mental model

Raw `for` loops are imperative: you describe *how* to do the work step-by-step. STL algorithms are declarative: you tell the compiler *what* you want done, and it figures out the fastest way to do it.

Beyond sorting and searching, the `<algorithm>` and `<numeric>` headers provide functional programming paradigms. `std::accumulate` folds/reduces an array into a single value. `std::transform` applies a function (like a map) to every element. Using these instead of raw loops makes code more expressive, safer, and open to compiler optimizations.

Explanation

**1. std::accumulate (The Reducer)**

Found in `<numeric>`, it sums up a range. `std::accumulate(vec.begin(), vec.end(), 0)` returns the sum of the vector. The `0` is critical: it sets the initial value AND the return type. If you accumulate floats but pass `0` (an integer) as the start, the result will be truncated to an integer! Pass `0.0` or `0.0f`.

**2. std::transform (The Mapper)**

It iterates through a range, applies a function (usually a lambda) to each element, and writes the result to an output iterator. **Crucial detail:** the destination must either already have enough pre-allocated size, OR you must use `std::back_inserter(dest_vec)` as the output iterator, which safely `.push_back()`s the new items. It's the C++ equivalent of JavaScript's `map()`.

**3. Common Queries**

- `std::count_if`: Counts elements matching a condition.

- `std::any_of` / `std::all_of`: Returns boolean if any/all elements match a condition.

- `std::find_if`: Returns an iterator to the first element matching a condition.

**Real-world Engineering:**

Replacing raw `for` loops with named algorithms is a major tenet of modern C++ (popularized by Sean Parent's "No Raw Loops" talk). A raw `for` loop forces the reader to parse every line of logic to understand the intent. Seeing `std::any_of` instantly communicates: "This block evaluates to a boolean based on a condition."

Code examples

Functional paradigms in C++

#include <vector>
#include <numeric>
#include <algorithm>
#include <iostream>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    
    // 1. Accumulate (Sum)
    // The '0' indicates the starting value is an int.
    int sum = std::accumulate(vec.begin(), vec.end(), 0);
    
    // 2. Count If
    // Count how many numbers are even using a lambda
    int evens = std::count_if(vec.begin(), vec.end(), [](int x) {
        return x % 2 == 0;
    });
    
    // 3. Any Of
    bool hasNegative = std::any_of(vec.begin(), vec.end(), [](int x) {
        return x < 0;
    });
    
    return 0;
}

These one-liners replace bulky loops and state variables, vastly reducing the surface area for logic errors (like off-by-one indices).

Key points

Common mistakes

Recall questions

Questions & answers

An interviewer asks you to check if an array of strings contains any empty strings. How would you do this in one line using an STL algorithm?

Using `std::any_of`: `bool hasEmpty = std::any_of(vec.begin(), vec.end(), [](const string& s){ return s.empty(); });`

Approach: Identify the correct algorithm to replace a search/boolean loop.

You are reviewing code that uses a manual `for` loop to convert an entire `std::vector<int>` into a `std::vector<string>` containing the string representations of the numbers. Which `<algorithm>` should they use instead?

They should use `std::transform`. They can pass the source begin/end iterators, a `std::back_inserter` to the destination string vector, and a lambda (or `std::to_string`) as the transformation function.

Approach: Recognize when `transform` (the map operation) is the right tool to convert data types between collections.

Continue learning

Previous: Custom comparators with lambda for sort/PQ

Return to C++ Roadmap