C++ 使用copy_if得到数组vector掩膜

假设给定一个数组vector<double> veca以及对应的掩膜(即指示标志数组)vector<bool> flags,得到veca中对应flags中为true的元素。html

假设veca{0.1, 0.2, 0.3, 0.4}flags{true, false, false, true},则vecb应该为{0.1, 0.4}ios

使用for循环天然能够很简单地解决这个问题,可是想要用标准模板库中的算法实现须要使用copy_if。使用copy算法的复制拷贝效率要比for的效率要高一些。c++

copy_if的由四个参数,前两个是输入元素的迭代器,拷贝两个迭代器之间的元素,第三个将元素拷贝到的位置,第四个是选择条件,即只拷贝改条件返回true的元素。算法

#include <vector>
#include <algorithm>
#include <iostream>
#include <numeric>    // accumulate
#include <iterator>

int main()
{
    std::vector<bool> flags{ true, true, false, true};
    std::vector<double> veca{ 0.1, 0.2, 0.3, -0.1 };
    
    std::vector<double> vecb;
    vecb.reserve(std::accumulate(flags.begin(), flags.end(), 0));
    
    // vecb在reserve以后并无未元素分配内存,插入应该使用back_inserter(vecb)
    // vecb在resize以后为元素分配了内存,使用back_inserter(vecb)会在已经分配内存的元素以后插入
    // 这时应该使用 vecb.begin(),对已经分配的内存进行覆盖
    size_t i = 0;
    std::copy_if(veca.begin(), veca.end(), std::back_inserter(vecb),
                [&i, &flags](double a){return flags[i++]; });
    
    for (auto &s : vecb)
        std::cout << s << std::endl;

//  i = 0;
//  std::vector<double> vecc;
//  std::remove_copy_if(veca.begin(), veca.end(), std::back_inserter(vecc),
//      [&i, &flags](double a){return flags[i++]; });
//  std::cout << "veca\n";
//  for (auto& s : veca)
//      std::cout << s << "\t";
//  std::cout << "\nvecc\n";
//  for (auto& s : vecc)
//      std::cout << s << "\t";
    return 0;
}

使用lambda表达式做为第四个元素,捕获掩膜数组flags和元素序号i
注意lambda表达式中flagsi都是使用的引用捕获,对于数组等数据结构要使用引用捕获,并且咱们但愿在lambda表达式中改变i的值,所以i也要是用引用捕获。
关于C++ lambda表达式更加详细的说明可参考博客博客数组

要注意的是reserveresize的不一样。数据结构

  • reserve只调整数组的capacity,并不分配元素分配内存,所以须要则copy_if的第三个参数使用back_insterter
  • resize为元素分配好了空间,若是在copy_if的第三个参数使用back_inserter,则会在已经分配内存的元素后面插入,正确地作法是使用vecb.begin(),对已经分配内存的元素进行覆盖。

remove_copy_if感受和copy_if差很少,就是逻辑相反,使用remove_copy_if会在第三个参数的位置上收集到第四个参数返回false的元素。具体差异还要在继续查查资料。code

相关文章
相关标签/搜索