假设给定一个数组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表达式中flags
和i
都是使用的引用捕获,对于数组等数据结构要使用引用捕获,并且咱们但愿在lambda表达式中改变i
的值,所以i
也要是用引用捕获。
关于C++ lambda表达式更加详细的说明可参考博客和博客。数组
要注意的是reserve
与resize
的不一样。数据结构
reserve
只调整数组的capacity,并不分配元素分配内存,所以须要则copy_if
的第三个参数使用back_insterter
;resize
为元素分配好了空间,若是在copy_if
的第三个参数使用back_inserter
,则会在已经分配内存的元素后面插入,正确地作法是使用vecb.begin()
,对已经分配内存的元素进行覆盖。remove_copy_if
感受和copy_if
差很少,就是逻辑相反,使用remove_copy_if
会在第三个参数的位置上收集到第四个参数返回false的元素。具体差异还要在继续查查资料。code