2010-12-18 14 views
36

ठीक है, मुझे उम्मीद है कि मैंने यहां एक गूंगा गलती की है। मेरे पास DisplayDevice3d की एक सूची है और प्रत्येक DisplayDevice3d में DisplayMode3d की एक सूची है। मैं DisplayDevice3d की सूची से सभी आइटम को हटाना चाहता हूं जिसमें कोई DisplayMode3d नहीं है। मैं भले ही MyDisplayDevices में 6 DisplayMode3d के से बाहर है, केवल 1 इसके मोड संग्रह में किसी भी DisplayMode3d की है, एक लैम्ब्डा उपयोग करने के लिए यह करने के लिए कोशिश कर रहा हूँ यानी .:std :: remove_if - lambda, संग्रह से कुछ भी नहीं हटा रहा

// If the device doesn't have any modes, remove it. 

    std::remove_if(MyDisplayDevices.begin(), MyDisplayDevices.end(), 
    [](DisplayDevice3d& device) 
    { 
    return device.Modes.size() == 0; 
    } 
); 

, कुछ भी सूची से हटा दिया जा रहा है।

मैंने यहां कितनी गलती की है?

संपादित करें: पी:

आह ठीक है, मेरी गलती मैं MyDisplayDevices.remove_if बजाय का उपयोग करना चाहिए था std :: remove_if की, फिर भी नीचे जवाब std :: remove_if के उपयोग के लिए सही हैं।

MyDisplayDevices.remove_if([](DisplayDevice3d const & device) 
          { 
           return device.Modes.size() == 0; 
          }); 
+3

कंटेनर ही remove_if तब तक हर तरह इसका इस्तेमाल का समर्थन करता है। मेरा मानना ​​है कि यह std :: सूची के साथ मामला है।कंटेनरों के लिए, जो remove_if की पेशकश नहीं करते हैं, आप कंटेनर के मिट सदस्य फ़ंक्शन के साथ संयोजन में std :: remove_if का उपयोग कर सकते हैं। – sellibitze

+0

@sellibitze दूसरे शब्दों में, चूहे के जहर – bobobobo

+0

[वेक्टर से तत्वों को मिटाकर] के संभावित डुप्लिकेट (http://stackoverflow.com/questions/347441/erasing-elements-from-a-vector) – bobobobo

उत्तर

63

आप को मिटा इटरेटर remove_if से लौटे पर कॉल करने के लिए की जरूरत है, वह कुछ इस तरह दिखना चाहिए: दूसरों

auto new_end = std::remove_if(MyDisplayDevices.begin(), MyDisplayDevices.end(), 
           [](const DisplayDevice3d& device) 
           { return device.Modes.size() == 0; }); 

MyDisplayDevices.erase(new_end, MyDisplayDevices.end()); 
+0

महान काम करता है। धन्यवाद। – Robinson

+0

[इस पर एक और ले लो] (http://stackoverflow.com/a/10360617/111307) – bobobobo

17

remove_if यह सिर्फ उन्हें ले जाता है समाप्त करने के लिए सूची में से कुछ भी नहीं निकालता है। आपको इसे erase के साथ उपयोग करने की आवश्यकता है। अधिक जानकारी के लिए यह question देखें।

+1

तो मैं पुनरावर्तक से मिटा देता हूं यह सूची के अंत में वापस आता है? – Robinson

+0

@ रॉबिन्सन: हाँ। – Asha

+4

"बस उन्हें अंत तक ले जाता है" बिल्कुल सही नहीं है। – sellibitze

2

के रूप में उल्लेख किया है, वहाँ यह काम करने के लिए तरीके हैं। हालांकि मेरी सलाह पूरी तरह से remove_if से बचने के लिए होगी और इसके बजाय एक मानक इटरेटर-आधारित हटाने के लिए चिपके रहेंगे। नीचे मुहावरे list और vector दोनों के लिए काम करता है और अप्रत्याशित व्यवहार नहीं करता है।

for(vector<TYPE>::iterator iter = vec.begin() ; iter != vec.end() ;) 
    if(iter->shouldRemove) 
    iter = vec.erase(iter) ; // advances iter 
    else 
    ++iter ; // don't remove 

उल्लेख नीचे टिप्पणी के रूप में, इस विधि जब 1 से अधिक तत्व निकाल दिया जाता है remove_if से अधिक लागत के होता है।

remove_if वेक्टर में आगे से तत्वों की प्रतिलिपि बनाकर काम करता है, और ओवरराइटिंग वेक्टर जिन्हें वेक्टर से तुरंत हटा दिया जाना चाहिए। उदाहरण के लिए: remove_if एक वेक्टर पर बुलाया सभी 0 तत्वों को दूर करने के:

0 1 1 0 1 0 

परिणामों में:

1 1 1 0 1 0 

सूचना कैसे वेक्टर अभी तक सही नहीं है। ऐसा इसलिए है क्योंकि remove_if अंतिम मान्य तत्व में एक पुनरावर्तक लौटाता है ... यह स्वचालित रूप से वेक्टर का आकार बदलता नहीं है। आपको अभी भी पर कॉल करने के लिए पर कॉल करने की आवश्यकता है।

एक उदाहरण का आकार बदलने प्रदर्शन नहीं करता नीचे

#include <stdio.h> 
#include <vector> 
#include <algorithm> 
#include <functional> 
using namespace std; 

void print(vector<int> &v) 
{ 
    for(int i : v) 
    printf("%d ", i); 
    puts(""); 
} 

int main() 
{ 
    vector<int> v = { 0, 1, 1, 0, 1, 0 }; 
    print(v); // 0 1 1 0 1 0 
    vector<int>::iterator it = remove_if(v.begin(), v.end(), [](int i){ return i == 0; }); 
    print(v); // 1 1 1 0 1 0 
    v.erase(it, v.end()); // actually cut out values not wanted in vector 
    print(v); // 1 1 1 (correct) 
} 
+3

आप इस विधि को * remove_if() * पर क्यों अनुशंसा करेंगे? निश्चित रूप से * remove_if() * "अप्रत्याशित व्यवहार" उत्पन्न नहीं करता है (यह केवल खराब नाम = पी है)। और std :: remove_if() संकलक के लिए समझदारी से अनुकूलित करने के लिए और अवसर प्रदान करेगा, है ना? क्योंकि यह शुरुआत से अंत तक चलता है, जबकि * संकलक को गारंटी देता है कि मैन्युअल रूप से पुनरावृत्ति के विपरीत, कोई मजाकिया व्यवसाय नहीं चल रहा है। (यानी वही अनुकूलन लाभ * श्रेणी-के लिए() * नियमित * से अधिक है() *) –

+5

bobobobo: समस्या यह है कि आपका एल्गोरिदम वेक्टर के लिए धीमा है। प्रत्येक 'मिटा' शेष तत्वों को एक से नीचे स्थानांतरित कर देगा। यदि आप 1000 में से 50 तत्वों को मिटा रहे हैं, तो यह ~ 50,000 चाल है, जहां आपको केवल अंतिम स्लॉट में बचे हुए लोगों की ~ 1000 चाल की आवश्यकता होती है। –

5

remove_if है, लेकिन इसके बजाय यह सिर्फ तत्व यह है कि नहीं हटाया पिछले तत्व इस प्रकार के iterator देता है। साफ करने के लिए यह इटरेटर erase() पर पारित किया जा सकता है।

enter image description here

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