# std::ranges::count, std::ranges::count_if

< cpp‎ | algorithm‎ | ranges

定义于头文件 `<algorithm>` |  |
调用签名 |  |
template< std::input_iterator I, std::sentinel_for<I> S, class T, class Proj = std::identity > requires std::indirect_binary_predicate<ranges::equal_to, std::projected<I, Proj>, const T*> constexpr std::iter_difference_t<I> count( I first, S last, const T& value, Proj proj = {} ); | (1) | (C++20 起)
template< ranges::input_range R, class T, class Proj = std::identity > requires std::indirect_binary_predicate<ranges::equal_to, std::projected<ranges::iterator_t<R>, Proj>, const T*> constexpr ranges::range_difference_t<R> count( R&& r, const T& value, Proj proj = {} ); | (2) | (C++20 起)
template< std::input_iterator I, std::sentinel_for<I> S, class Proj = std::identity, std::indirect_unary_predicate<std::projected<I, Proj>> Pred > constexpr std::iter_difference_t<I> count_if( I first, S last, Pred pred = {}, Proj proj = {} ); | (3) | (C++20 起)
template< ranges::input_range R, class Proj = std::identity, std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>> Pred > constexpr ranges::range_difference_t<R> count_if( R&& r, Pred pred = {}, Proj proj = {} ); | (4) | (C++20 起)

返回范围 `[first, last)` 中满足特定判别标准的的元素数。

1) 计数等于 `value` 的元素数。
3) 计数谓词 `p` 对其返回 true 的元素数。
2,4) 同 (1,3) ，但以 `r` 为源范围，如同以 ranges::begin(r) 为 `first` 并以 ranges::end(r) 为 `last` 。

此页面上描述的仿函数实体是 niebloid ，即：

- 调用它们中的任何一者时不可指定显式模板实参。
- 它们无一对实参依赖查找可见。
- 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

### 参数

first, last | - | 要检验的元素范围
r | - | 要检验的元素范围
value | - | 要搜索的值
pred | - | 应用到被投影元素的谓词
proj | - | 应用到元素的投影

### 返回值

范围中满足条件的元素数。

### 复杂度

准确比较和应用投影 `last` - `first` 次。

### 注解

对于无任何判别标准的范围中的元素数，见 std::ranges::distance 。

### 可能的实现

版本一
    struct count_fn {
      template< std::input_iterator I, std::sentinel_for<I> S,
              class T, class Proj = std::identity >
      requires std::indirect_binary_predicate<ranges::equal_to, std::projected<I, Proj>,
                                            const T*>
      constexpr std::iter_difference_t<I>
        operator()( I first, S last, const T& value, Proj proj = {} ) const
      {
        std::iter_difference_t<I> counter = 0;
        for (; first != last; ++first) {
          if (std::invoke(proj, *first) == value)
          {
            ++counter;
          }
        }

        return counter;
      }

      template< ranges::input_range R, class T, class Proj = std::identity >
      requires std::indirect_binary_predicate<ranges::equal_to,
                                              std::projected<ranges::iterator_t<R>, Proj>,
                                              const T*>
      constexpr ranges::range_difference_t<R>
        operator()( R&& r, const T& value, Proj proj = {} ) const
      {
        return (*this)(ranges::begin(r), ranges::end(r), value, std::ref(proj));
      }
    };

    inline constexpr count_fn count;
版本二
    struct count_if_fn {
      template< std::input_iterator I, std::sentinel_for<I> S,
                class Proj = std::identity,
                std::indirect_unary_predicate<std::projected<I, Proj>> Pred >
      constexpr std::iter_difference_t<I>
        operator()( I first, S last, Pred pred = {}, Proj proj = {} ) const
      {
        std::iter_difference_t<I> counter = 0;
        for (; first != last; ++first) {
          if (std::invoke(pred, std::invoke(proj, *first)))
          {
            ++counter;
          }
        }

        return counter;
      }

      template< ranges::input_range R, class Proj = std::identity,
                std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>> Pred >
      constexpr ranges::range_difference_t<R>
        operator()( R&& r, Pred pred = {}, Proj proj = {} ) const
      {
        return (*this)(ranges::begin(r), ranges::end(r),
                       std::ref(pred), std::ref(proj));
      }
    };

    inline constexpr count_if_fn count_if;

### 示例

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

    int main()
    {
        std::vector<int> v{ 1, 2, 3, 4, 4, 3, 7, 8, 9, 10 };

        namespace ranges = std::ranges;

        // 确定 std::vector 中有多少整数匹配目标值。
        int target1 = 3;
        int target2 = 5;
        int num_items1 = ranges::count(v.begin(), v.end(), target1);
        int num_items2 = ranges::count(v, target2);
        std::cout << "number: " << target1 << " count: " << num_items1 << '\n';
        std::cout << "number: " << target2 << " count: " << num_items2 << '\n';

        // 用 lambda 表达式计数被 3 整除的元素。
        int num_items3 = ranges::count_if(v.begin(), v.end(), [](int i){return i % 3 == 0;});
        std::cout << "number divisible by three: " << num_items3 << '\n';

        // 用 lambda 表达式计数被 11 整除的元素。
        int num_items11 = ranges::count_if(v, [](int i){return i % 11 == 0;});
        std::cout << "number divisible by eleven: " << num_items11 << '\n';
    }

输出：

    number: 3 count: 2
    number: 5 count: 0
    number divisible by three: 3
    number divisible by eleven: 0

### 参阅

ranges::distance (C++20) | 返回迭代器与哨位间的距离，或范围起始与结尾间的距离 (niebloid)
ranges::take_while_view views::take_while (C++20) | 由另一 `view` 的到首个谓词返回 `false` 为止的起始元素组成的 `view` (类模板) (范围适配器对象)
count count_if | 返回满足指定判别标准的元素数 (函数模板)