2008-10-24 70 views
12

我有我需要工作在元素的集合,在收集調用成員函數:使用STL找到一個向量的所有元素

std::vector<MyType> v; 
... // vector is populated 

對於調用不帶參數的功能,這是很直接的:

std::for_each(v.begin(), v.end(), std::mem_fun(&MyType::myfunc)); 

類似的事情可以,如果有一個參數我想調用該函數來完成。

我的問題是,我想調用向量中的元素的函數,如果它滿足某些條件。 std::find_if將迭代器返回到滿足謂詞條件的第一個元素。

std::vector<MyType>::iterator it = 
     std::find_if(v.begin(), v.end(), MyPred()); 

我希望能夠找到滿足謂詞的所有元素並通過它們進行操作。

我一直在尋找的STL算法爲「find_all」或「​​」等同,還是有辦法,我可以與現有的STL做到這一點(例如,我只需要重複一次),而不是滾動我自己或簡單地使用for循環和比較來執行標準迭代。

回答

19

Boost Lambda使這一切變得簡單。

#include <boost/lambda/lambda.hpp> 
#include <boost/lambda/bind.hpp> 
#include <boost/lambda/if.hpp> 

std::for_each(v.begin(), v.end(), 
       if_(MyPred())[ std::mem_fun(&MyType::myfunc) ] 
      ); 

如果它很簡單,你甚至可以不用定義MyPred()。這是lambda真正閃耀的地方。例如,如果MyPred意味着 「是能被2整除」:

std::for_each(v.begin(), v.end(), 
       if_(_1 % 2 == 0)[ std::mem_fun(&MyType::myfunc) ] 
      ); 


更新: 這樣做與的C++ 0x lambda語法也很不錯(與謂語模2繼續):

std::for_each(v.begin(), v.end(), 
       [](MyType& mt) mutable 
       { 
       if(mt % 2 == 0) 
       { 
        mt.myfunc(); 
       } 
       }); 

乍一看,這看起來像是自boost :: lambda語法倒退,但是,它是更好,因爲更復雜的函子的邏輯是瑣碎的C++ 0x語法來實現...boost :: lambda中任何非常複雜的東西都會很快變得棘手。 Microsoft Visual Studio 2010 beta 2目前實現了此功能。

6

可以更改矢量嗎?你可能想看看分區算法。
Partition algorithm

另一種辦法是改變你的MyType::myfunc要麼檢查元素,或採取謂詞作爲參數,並用它來測試它的經營上的元素。

+0

分區會工作在一般情況下,但對於這種特殊情況下,它不會工作,因爲向量不能改變。 – twokats 2008-11-07 20:34:11

12

我寫了一個for_each_if()和一個for_each_equal()這做我認爲你在找什麼。

for_each_if()需要謂詞函子,以評估平等,和for_each_equal()採取任何類型的值並執行使用operator ==的直接比較。在這兩種情況下,您傳入的函數都會在通過相等性測試的每個元素上調用。

/* --- 

    For each 
    25.1.1 

     template< class InputIterator, class Function, class T> 
      Function for_each_equal(InputIterator first, InputIterator last, const T& value, Function f) 

     template< class InputIterator, class Function, class Predicate > 
      Function for_each_if(InputIterator first, InputIterator last, Predicate pred, Function f) 

    Requires: 

     T is of type EqualityComparable (20.1.1) 

    Effects:  

     Applies f to each dereferenced iterator i in the range [first, last) where one of the following conditions hold: 

      1: *i == value 
      2: pred(*i) != false 

    Returns:  

     f 

    Complexity: 

     At most last - first applications of f 

    --- */ 

    template< class InputIterator, class Function, class Predicate > 
    Function for_each_if(InputIterator first, 
         InputIterator last, 
         Predicate pred, 
         Function f) 
    { 
     for(; first != last; ++first) 
     { 
      if(pred(*first)) 
       f(*first); 
     } 
     return f; 
    }; 

    template< class InputIterator, class Function, class T> 
    Function for_each_equal(InputIterator first, 
          InputIterator last, 
          const T& value, 
          Function f) 
    { 
     for(; first != last; ++first) 
     { 
      if(*first == value) 
       f(*first); 
     } 
     return f; 
    }; 
+0

+1發佈的工作代碼,正是我正在尋找。 – 2011-11-30 17:25:02

+0

謝謝。哇,這是一位老人! – 2011-11-30 17:29:44

0

爲了什麼它的價值for_each_if被視爲最終除了提升。實現你自己並不難。

0

的Lamda功能 - 的想法是做這樣的事情

for_each(v.begin(), v.end(), [](MyType& x){ if (Check(x) DoSuff(x); }) 

Origial發佈here

0

您可以使用Boost.Foreach

BOOST_FOREACH (vector<...>& x, v) 
{ 
    if (Check(x) 
     DoStuff(x); 
} 
+0

我也可以使用傳統的for循環。這並沒有解決希望使用STL算法來用謂詞編寫for_each的更清晰版本的問題。 Lamdba很優雅地解決了這個問題。 – twokats 2008-11-07 20:32:46

1
std::vector<int> v, matches; 
std::vector<int>::iterator i = v.begin(); 
MyPred my_pred; 
while(true) { 
    i = std::find_if(i, v.end(), my_pred); 
    if (i == v.end()) 
     break; 
    matches.push_back(*i); 
} 

爲了記錄在案,而我曾經見過呼籲一個listend()的實現是O(n)的,我還沒有看到任何STL實現中在vector上調用end()是O(1)以外的任何內容 - 主要是因爲vector確保具有隨機訪問迭代器。

即便如此,如果你擔心低效end(),您可以使用此代碼:

std::vector<int> v, matches; 
std::vector<int>::iterator i = v.begin(), end = v.end(); 
MyPred my_pred; 
while(true) { 
    i = std::find_if(i, v.end(), my_pred); 
    if (i == end) 
     break; 
    matches.push_back(*i); 
} 
相關問題