假設給定一個數組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