An introduction to the 5 main counting algorithms in the C++ standard library:

`count()`

, `count_if()`

, `any_of()`

, `none_of()`

, and `all_of()`

Updated

Let's take a look at some useful counting algorithms available in the standard library. To access these, we need the `<algorithm>`

Â header:

`#include <algorithm>`

In this lesson, we cover the 5 most useful counting algorithms: `count()`

, `count_if()`

, `any_of()`

, `none_of()`

and `all_of()`

. Let's getÂ started!

`std::ranges::count()`

The `std::ranges::count`

algorithm requires two arguments - the range we want to run the algorithm in, and the element we want to count within thatÂ range.

Whether or not an element matches what weâ€™re looking for is determined by an equality check. Therefore, the type of elements in our collection must implement the equality operator, `==`

In this example, we count the number of `4`

s in our vector ofÂ integers:

```
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector Numbers { 1, 2, 3, 4, 4, 5 };
auto Fours { std::ranges::count(Numbers, 4) };
std::cout << "Count of fours: " << Fours;
}
```

`Count of fours: 2`

The return type of these algorithms can be somewhat cryptic. For `count()`

, the return type is aÂ template:

`std::ranges::range_difference_t`

Given weâ€™re counting elements in a `std::vector<int>`

in this case, the type returned from `count()`

would be even moreÂ verbose:

```
std::ranges::range_difference_t<std::vector<int>> Fours
{
std::ranges::count(Numbers, 4)
};
```

Itâ€™s common to just use `auto`

in this scenario, as we did in the original example. Alternatively, itâ€™s reasonable to implicitly cast the return value to something simpler, like a 64-bit integer or `size_t`

:

`int64_t Fours { std::ranges::count(Numbers, 4) };`

`std::ranges::count_if()`

The basic `std::ranges::count()`

algorithm uses the equality operator `==`

to determine if an element in our container matches the object weâ€™re lookingÂ for.

The `std::ranges::count_if()`

algorithm lets us change this behavior. Rather than using the `==`

operator to determine if two objects are equal, `count_if()`

uses a function, which we provide as anÂ argument.

The function will be called for every object in the collection, receiving that object as an argument. Our function should return `true`

if we want this object to be included in the count, and `false`

otherwise. A function that returns a boolean is also known as a * predicate*.

Below, we have a predicate that returns `true`

if a provided argument is even. We pass this predicate to `std::ranges::count_if()`

to count the number of elements in our range that areÂ even:

```
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector Numbers { 1, 2, 3, 4, 4, 5 };
auto isEven{[](int x) { return x % 2 == 0; }};
auto EvenCount {
std::ranges::count_if(Numbers, isEven)
};
std::cout << "Even Count: " << EvenCount;
}
```

`Even Count: 3`

`std::ranges::any_of()`

The `std::ranges::any_of()`

algorithm also accepts a predicate function. The algorithm will return `true`

if our predicate returns `true`

for * any* element in theÂ range.

In the following example, we return `true`

if * any* number in our collection isÂ even:

```
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector Numbers { 1, 2, 3, 4, 4, 5 };
auto isEven{[](int x) { return x % 2 == 0; } };
bool IncludesEven {
std::ranges::any_of(Numbers, isEven)};
std::cout << "An even number "
<< (IncludesEven ? "is" : "is not")
<< " included";
}
```

`An even number is included`

`count_if()`

vs `any_of()`

Algorithms like `any_of()`

may seem unnecessary, as we can get the same output with `count_if`

:

```
bool IncludesEven {
std::ranges::count_if(Numbers, isEven) > 0
};
```

Using `any_of()`

here would have twoÂ advantages:

- It better describes what our code is determining
- It results in better performance. After finding an even number,
`count_if()`

function continues to check the rest of our collection, even though doing so will not change the result of`IncludesEven`

.`any_of()`

stops as soon as it finds an object that causes our predicate to return`true`

.

Similar arguments are also true of the `none_of()`

and `all_of()`

algorithms, which weâ€™ll seeÂ next.

`std::ranges::none_of()`

The `std::ranges::none_of()`

algorithm will run a predicate on everything in our collection, and return `true`

if * every* predicate returns

`false`

.If our predicate returns `true`

for any element in the collection, the algorithm will stop evaluating further elements, and return `false`

.

```
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector Numbers { 1, 2, 3, 4, 4, 5 };
auto isEven{ [](int x) { return x % 2 == 0; } };
bool NoEvenNumbers {
std::ranges::none_of(Numbers, isEven)};
std::cout << "The range contains "
<< (NoEvenNumbers ? "no" : "some")
<< " even numbers";
}
```

`The range contains some even numbers`

This algorithm will return `true`

if the range has noÂ elements:

```
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> Numbers { };
auto isEven { [](int x) { return x % 2 == 0; } };
bool Result {
std::ranges::none_of(Numbers, isEven)};
std::cout << (Result ? "true" : "false");
}
```

`true`

`std::ranges::all_of()`

The `std::ranges::all_of()`

algorithm will run a predicate on everything in our collection, and return `true`

if * every* invocation of the predicate returns

`true`

.If our predicate returns `false`

for * any* element in the collection, the algorithm will stop evaluating further elements, and return

`false`

.```
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector Numbers { 1, 2, 3, 4, 4, 5 };
auto isEven{[](int x) { return x % 2 == 0; }};
bool AllEvenNumbers {
std::ranges::all_of(Numbers, isEven)};
std::cout << "The range is "
<< (AllEvenNumbers ? "all" : "NOT all")
<< " even numbers";
}
```

`The range is NOT all even numbers`

Note, that this algorithm will return `true`

if the range has noÂ elements:

```
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> Numbers{};
auto isEven{[](int x) { return x % 2 == 0; }};
bool Result{
std::ranges::all_of(Numbers, isEven)};
std::cout << Result ? "true" : "false";
}
```

`true`

Typically when using these algorithms, the predicates we need will be class methods of the objects contained within our range. When that is the case, we generally donâ€™t need to define a predicate function. We can just pass a reference to the classÂ method:

```
#include <algorithm>
#include <iostream>
#include <vector>
class Player {/*...*/};
int main() {
std::vector Party {
Player{"Roderick", 100},
Player{"Anna", 200},
Player{"Robert", 500}
};
bool EveryoneAlive{std::ranges::all_of(
Party, &Player::isAlive)};
std::cout << "Everyone "
<< (EveryoneAlive ? "is" : "is not")
<< " alive";
}
```

`Everyone is alive`

All the algorithms in this lesson accept an additional optional argument, which can be a projection function. We cover projection in detailÂ here:

In this example, we project the objects in our container to their absolute value before running the `count()`

algorithm. Two of those projections are equal to `1`

, so our algorithm returns `2`

:

```
#include <algorithm>
#include <iostream>
#include <vector>
int Projector(int x) { return std::abs(x); }
int main() {
std::vector Nums{-2, -1, 0, 1, 2};
auto Count {std::ranges::count(
Nums, 1, Projector)};
std::cout << "Count: " << Count;
}
```

`Count: 2`

In this example, we use `Player::GetName()`

as our projection function, projecting our `Player`

objects to a `std::string`

before comparing them to the `"Anna"`

Â string:

```
#include <algorithm>
#include <iostream>
#include <vector>
class Player {/*...*/};
int main() {
std::vector Party {
Player{"Roderick", 100},
Player{"Anna", 200},
Player{"Robert", 500}
};
auto AnnaCount{std::ranges::count(
Party, "Anna", &Player::GetName)};
std::cout << "AnnaCount: " << AnnaCount;
}
```

`AnnaCount: 1`

As we covered in the introduction to range-based algorithms, `std::ranges::count()`

and all the other algorithms we covered in this lesson allow us to define our range as an iterator-sentinelÂ pair.

Below, we use this technique to exclude the first and last objects from ourÂ count:

```
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector Numbers{1, 2, 3, 4, 4};
auto Fours{std::ranges::count(
Numbers.begin() + 1, Numbers.end() - 1, 4)};
std::cout << "Count of fours: " << Fours;
}
```

`Count of fours: 1`

The concept of a range was introduced in C++20. When targeting older specifications, we can use alternative versions of these algorithms that work directly with iteratorsÂ instead.

These are available by omitting the `ranges`

qualification from the identifiers. For example, the iterator variant of `std::ranges::count()`

is available as `std::count()`

:

```
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector Numbers{1, 2, 3, 4, 4, 5};
auto Fours{std::count(
Numbers.begin(), Numbers.end(), 4)};
std::cout << "Count of fours: " << Fours;
}
```

`Count of fours: 2`

In this lesson, we explored the counting algorithms that are part of the C++20 `std::ranges`

library, and available by including the `<algorithm>`

Â header.

- Understanding of
`std::ranges::count()`

for counting specific elements in a range. - Use of
`std::ranges::count_if()`

to count elements that meet a predicate condition. - Application of
`std::ranges::any_of()`

,`none_of()`

, and`all_of()`

for conditional checks across elements. - Insight into the performance benefits of using specific algorithms like
`any_of()`

over alternatives like`count_if()`

in certain scenarios. - Using predicates in customizing the behavior of counting algorithms.
- How to use member functions as predicates for more complex conditions.
- The role of projection functions in transforming elements before applying counting algorithms.
- Review of using iterator-sentinel pairs for defining custom ranges.

Was this lesson useful?

Updated

Lesson Contents### Counting Algorithms

An introduction to the 5 main counting algorithms in the C++ standard library: `count()`

, `count_if()`

, `any_of()`

, `none_of()`

, and `all_of()`

This lesson is part of theÂ course:### Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.