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

相關文章
相關標籤/搜索