2008-10-24 24 views
12

मैं तत्वों है कि मैं पर काम करने की जरूरत है की एक संग्रह है एक वेक्टर के सभी तत्वों को खोजने के लिए, संग्रह पर सदस्य कार्यों बुला:एसटीएल का उपयोग कर

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()); 

मैं विधेय बैठक सभी तत्वों खोजने के लिए और उन पर संचालित करने के लिए कामना करता हूं। बराबर, या एक तरह से मैं मौजूदा एसटीएल साथ ऐसा कर सकते हैं (जैसे कि मैं केवल एक बार पुनरावृति करने की जरूरत है), बजाय रोलिंग

मैं एक "find_all" या "do_if" के लिए एसटीएल एल्गोरिदम को देखकर किया गया है मेरी लूप और तुलना के लिए एक मानक पुनरावृत्ति या बस एक मानक पुनरावृत्ति करें।

उत्तर

19

बूस्ट लैम्ब्डा यह आसान बनाता है।

#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() को परिभाषित करने से भी दूर हो सकते हैं। यह वह जगह है जहां लैम्ब्डा वास्तव में चमकता है। उदाहरण के लिए, अगर MyPred मतलब था "2 से विभाज्य है":

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


अद्यतन: C++ 0x लैम्ब्डा सिंटैक्स के साथ ऐसा करने से भी (सापेक्ष 2 के रूप में विधेय के साथ जारी रखने) बहुत अच्छा है:

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

पहली नज़र में इस बढ़ावा :: लैम्ब्डा वाक्य रचना से एक कदम पीछे की ओर की तरह दिखता है, तथापि, यह बेहतर है क्योंकि अधिक जटिल functor तर्क C++ 0x वाक्य रचना के साथ लागू करने के लिए तुच्छ है ...जहां बूस्ट में बहुत जटिल कुछ भी है :: लैम्ब्डा जल्दी से मुश्किल हो जाता है। माइक्रोसॉफ्ट विजुअल स्टूडियो 2010 बीटा 2 वर्तमान में इस कार्यक्षमता को लागू करता है।

6

क्या वेक्टर को बदलना ठीक है? आप विभाजन एल्गोरिदम को देखना चाह सकते हैं।
Partition algorithm

एक अन्य विकल्प अपने MyType::myfunc या तो जाँच करने के लिए तत्व को बदलने के लिए, या एक पैरामीटर के रूप में एक विधेय लेगी और उसका उपयोग तत्व उस पर काम कर रहा है परीक्षण करने के लिए होगा।

+0

विभाजन एक सामान्य स्थिति में काम करेगा लेकिन यह काम नहीं करेगा इस विशिष्ट मामले के लिए, वेक्टर के रूप में नहीं बदल सकते हैं:

फिर भी, अगर आप एक अक्षम end() को लेकर चिंतित हैं, तो आप इस कोड का उपयोग कर सकते । – twokats

12

मैंने for_each_if() और for_each_equal() लिखा जो मुझे लगता है कि आप क्या देख रहे हैं।

for_each_if() समानता का मूल्यांकन करने के लिए एक विधेय functor लेता है, और 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 कार्य कोड पोस्ट करने के लिए +1 जो ठीक वही करता है जो मैं ढूंढ रहा था। –

+0

धन्यवाद। वाह, यह एक बूढ़ा था! –

0
क्या इसके लायक for_each_if बढ़ावा देने के लिए एक अंतिम अतिरिक्त के रूप में विचार किया जा रहा है के लिए

। अपने आप को लागू करना मुश्किल नहीं है।

0

Lamda कार्य - विचार इस

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

की तरह कुछ करने के लिए origial here पोस्ट है। रिकॉर्ड के लिए

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

आप Boost.Foreach उपयोग कर सकते हैं पर vector पर कॉल करना ओ (1) के अलावा कुछ भी था - मुख्य रूप से क्योंकि vector एस को यादृच्छिक-पहुंच वाले इटरेटर्स की गारंटी है।

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); 
} 
+0

मैं पारंपरिक लूप के लिए भी पारंपरिक उपयोग कर सकता हूं। यह एक अनुमान के साथ for_each के क्लीनर संस्करण को लिखने के लिए एसटीएल एल्गोरिदम का उपयोग करने की इच्छा की समस्या का समाधान नहीं करता है। Lamdba इस समस्या को काफी सुंदर ढंग से हल करें। – twokats

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); 
} 

, जबकि मैं एक कार्यान्वयन जहां एक list पर end() बुला देखा है था हे (एन), मैं किसी भी एसटीएल कार्यान्वयन जहां नहीं देखा है:

+0

I से v.end() से find_if द्वारा आप इस लूप की जटिलता को आधा कर सकते हैं। यह वर्गबद्ध है, हालांकि ... -1 – xtofl

+0

मूल कोड में मेरी त्रुटि को इंगित करने के लिए धन्यवाद। कोड अब ओ (एन) है: शुरुआत से शुरू करें -> पहले मैच को ढूंढें और इसे स्टोर करें -> उस स्थिति से शुरू करें, अगला मैच ढूंढें और इसे स्टोर करें -> अंत तक पहुंचने तक जारी रखें। –

+0

* MyPred * के बावजूद, यह कोड * v * से * मैचों * का पहला तत्व नहीं जोड़ देगा? –

संबंधित मुद्दे