C/C++ Arena

Step 3 of 6

find_if, count_if, any_of

A predicate is a function that takes one element and returns bool: "is it negative?", "is it longer than 5?". A whole family of algorithms takes a predicate:

Algorithm Returns
std::find_if(first, last, pred) iterator to the first match, or last
std::count_if(first, last, pred) how many elements match
std::any_of, std::all_of, std::none_of bool
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

int main() {
    std::vector<std::string> files = {"notes.txt", "photo.jpg", "todo.txt", "song.mp3"};

    auto is_txt = [](const std::string& f) {
        return f.size() >= 4 && f.substr(f.size() - 4) == ".txt";
    };
    std::cout << std::count_if(files.begin(), files.end(), is_txt) << " text files\n";

    auto it = std::find_if(files.begin(), files.end(), [](const std::string& f) {
        return f.starts_with("photo");
    });
    if (it != files.end()) std::cout << "found " << *it << "\n";

    bool all_named = std::all_of(files.begin(), files.end(), [](const std::string& f) {
        return f.find('.') != std::string::npos;
    });
    std::cout << "all have extensions: " << all_named << "\n";
}
2 text files
found photo.jpg
all have extensions: 1

Checking the end of a string

"Does this string end with X?" comes up constantly. Two ways:

Why not a loop?

A loop works, of course. But count_if(..., is_txt) reads like the sentence "count the ones that are text files", and there's no counter to initialize or index to get wrong. Naming the predicate, as is_txt does, makes it even clearer.

Your turn: write int count_headshots(const std::vector<std::string>& kills) counting entries that end with "_hs", using std::count_if and a lambda.

Previous: Lambdas Next: accumulate and transform