查找具有偶数值的矢量元素

Find vector elements with even values

本文关键字:元素 查找      更新时间:2023-10-16

你能解释一下这段代码是如何工作的吗。它成功地计算了具有偶数值的向量元素,但我不清楚在这种特殊情况下绑定是如何工作的。

count_if(vec.begin(), vec.end(),
         std::bind(logical_not<bool>(),
                   std::bind(modulus<int>(), placeholders::_1, 2)));

请注意,您发布的代码计算向量中的偶数而不是奇数:

count_if(vec.begin(), vec.end(),
         bind(logical_not<bool>(),
              bind(modulus<int>(), placeholders::_1, 2)));

count_if是一种算法,它返回指定范围内满足特定标准的元素数量:

count_if(first, last, criteria)

在您的情况下,firstvec.begin()lastvec.end():因此计数考虑整个向量。

现在让我们把注意力集中在标准部分。

由内而外:

modulus<int>是一个函数对象,它返回整数除法的余数(就像%运算符一样)。它有两个参数:第一个参数表示为placeholders::_1,它是源向量中的泛型元素。可以将其视为扫描整个矢量内容的变量x

第二个参数是数字2,因为要检查整数是偶数还是奇数,可以计算x % 2并将结果与0:进行比较

x % 2 == 0 --> even number
x % 2 == 1 --> odd number

bind用于指定modulus函数对象的参数。

该模运算的结果被作为另一个函数对象logical_not<bool>的输入。这只是否定输入,例如,如果输入是false(0),则logical_not<bool>返回true,反之亦然。

因此,"计数标准"由以下操作流程表示:

  1. 使用modulus计算:placeholders::_1 % 2,即<<generic vector element>> % 2
  2. 如果以上操作的结果是0(false),则使用logical_not返回true(反之亦然)

所以,如果一个数字是偶数:

  1. even number % 2 == 0
  2. 否定0得到true

相反,如果一个数字是奇数:

  1. odd number % 2 == 1
  2. 否定1得到false

由于count_if计算标准为true的元素数,因此您正在计算向量中的偶数数。

如果你真的想计算向量中的奇数,你可以去掉逻辑反转(即logical_not):

auto odds = count_if(vec.begin(), vec.end(),
                     bind(modulus<int>(), placeholders::_1, 2));    

注意,在这种情况下,使用moduluslogical_not的函数方法似乎太复杂了:使用lambda(甚至特设IsEven()简单函数)会更清楚
考虑以下代码(位于Ideone上)来比较这三种方法:

#include <algorithm>
#include <functional>
#include <iostream>
#include <vector>
using namespace std;
bool IsEven(int n) {
    return (n % 2) == 0;
}
int main() {
    // Test vector
    vector<int> vec{ 11, 22, 33, 44, 55 };
    // Using functional approach
    auto n = count_if(vec.begin(), vec.end(),
         bind(logical_not<bool>(),
             bind(modulus<int>(), placeholders::_1, 2)));    
    cout << n << endl;
    // Using lambdas
    n = count_if(vec.begin(), vec.end(), 
                 [](int n) { return (n % 2) == 0; });
    cout << n << endl;
    // Using boolean returning ad hoc function
    n = count_if(vec.begin(), vec.end(), IsEven);
    cout << n << endl;
}

从内部调用到外部调用的解锁:

modulus<int>( a, 2 )

返回除以2后的余数:==0或=0.

logical_not<bool>( x )

进行x的逻辑反转(因此0/false变为1/true,1/true变为0/false)

count_if(from, to, cond )

从/到计算迭代器定义的所有元素的cond(反向模数)。

placeholders::_1是将count_if运行的迭代器驱动循环中确定的内容(即当前元素)插入下面嵌套的函数的硬连线方式。

这不计算奇数元素,而是偶数元素

要计算具有奇数值的矢量元素,我们必须检查每个元素是否除以2,如果结果为1,则返回true。

因此,我们将使用modulus(),它是一个实现运算符()的函数对象

constexpr T operator()( const T& lhs, const T& rhs ) const;

并返回lhs除以rhs的余数。

我们必须使用std::bind来粘合一个并且只有一个参数传递给

count_if( InputIt first, InputIt last, UnaryPredicate p )

一元谓词p(这里是我们的模)到模的第一个自变量,常数2到第二个

std::bind(modulus<int>(), placeholders::_1, 2))

现在我们的函数std::bind(modulus<int>(), placeholders::_1, 2))返回true(1),如果参数是奇数,则返回false(0),如果变量是偶数。如果我们想计算偶数个自变量,我们必须忽略这一点,所以我们的谓词必须返回相反的结果:

std::bind(logical_not<bool>(),
                           std::bind(modulus<int>(), placeholders::_1, 2))

http://ideone.com/80VmsZ

正如Mike Seymour所建议的,更简单、更干净的设计将是用短lambda函数代替这种绑定:

[](int x){return x % 2 == 0;} // to count even elements
[](int x){return x % 2 != 0;} // to count odds

这是一个双绑定,第一个通过参数的2计算modulus,这似乎相当于

y = x % 2

然后将结果绑定到logical_not,以反转结果。