std::count_if配合lambda是最直接标准库方案,需手动提供判断逻辑,不依赖数组类型,适用于原生数组和std::vector等,要求显式写出条件如x>=3&&x

用 std::count_if 配合 lambda 最直接
标准库的 std::count_if 是最常用、也最不容易出错的选择。它不关心数组是原生数组还是 std::vector,只要传入合法的迭代器范围即可。
关键点在于:必须自己提供判断逻辑(lambda 或函数对象),不能只靠“范围”自动截取——C++ 数组本身没有内置的“值域过滤”能力。
示例(统计 arr 中值在 [3, 7] 内的元素个数):
int arr[] = {1, 3, 5, 7, 9, 4, 6};
size_t n = sizeof(arr) / sizeof(arr[0]);
auto count = std::count_if(arr, arr + n, [](int x) { return x >= 3 && x
- 注意
arr + n是右开区间,别写成arr + n - 1 - lambda 捕获为空即可,无需捕获外部变量
- 如果范围是开区间(如
(3, 7)),条件改为x > 3 && x
原生数组用 std::begin/std::end 更安全
手动算 sizeof 容易在传参后失效(数组退化为指针),所以优先用 std::begin 和 std::end 获取迭代器。
这对 C++11 及以上有效,且能避免误传指针导致的越界计数。
int arr[] = {2, 4, 6, 8, 10};
auto count = std::count_if(std::begin(arr), std::end(arr),
[](int x) { return x % 2 == 0; }); // 全是偶数,count == 5
-
std::end(arr)返回的是“末尾之后”的位置,符合 STL 迭代器约定 - 若函数接收的是
int*参数,则无法用std::begin/end,此时必须额外传长度 - 对
std::vector同样适用:std::count_if(v.begin(), v.end(), ...)
性能敏感时避免重复计算边界条件
如果同一组数据要反复按不同范围统计(比如做直方图),每次都跑 std::count_if 是 O(n) 开销。此时可先排序 + 二分查找,把单次查询降到 O(log n)。
但注意:排序会改变原始顺序,且仅当查询次数 ≫ 1 时才值得优化。
std::vector<int> v = {1, 5, 3, 9, 4, 7};
std::sort(v.begin(), v.end()); // → {1,3,4,5,7,9}
auto lo = std::lower_bound(v.begin(), v.end(), 3); // 第一个 ≥3 的位置
auto hi = std::upper_bound(v.begin(), v.end(), 7); // 第一个 >7 的位置
size_t count = std::distance(lo, hi); // count == 4 (3,4,5,7)
</int>
-
std::lower_bound和std::upper_bound要求容器已排序 - 别混淆
upper_bound(>value)和lower_bound(≥value) - 对小数组(count_if 通常更快,别过早优化
用 std::ranges::count_if(C++20)更简洁
C++20 引入了 std::ranges,支持直接传整个数组或视图,不用手动拆迭代器。
语法更接近直觉,但需确认编译器支持(GCC 10+、Clang 10+、MSVC 19.28+)。
#include <ranges>
int arr[] = {1, 2, 3, 4, 5};
auto count = std::ranges::count_if(arr, [](int x) { return x > 2; }); // count == 3
</ranges>
- 不需要显式写
std::begin/std::end,底层自动推导 - 对
std::vector、std::array、原生数组都统一支持 - 如果项目还停留在 C++17 或更早,这个选项不可用
最容易被忽略的是:C++ 里“范围”从来不是数组的固有属性,所有所谓“范围内计数”本质都是“遍历 + 条件判断”。别指望编译器自动理解你心里想的 [min, max] 区间——条件逻辑必须明确写出,哪怕只有一行 lambda。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











