2011-12-21 7 views
16

मैं जैसे लूप के साथ एक वेक्टर के माध्यम से लूपिंग कर रहा हूं। इस लूप के भीतर, मैं उस वेक्टर इंडेक्स पर तत्व पर एक शर्त की जांच करता हूं, और यदि कोई निश्चित स्थिति सत्य है, तो मैं उस तत्व को हटाना चाहता हूं।उस पर लूप करते समय वेक्टर से तत्व को कैसे हटाएं?

क्रैश किए बिना इसे लूप करते समय मैं वेक्टर तत्व कैसे हटा सकता हूं?

+4

आप शायद 'remove_if' और' मिटा 'का उपयोग कर सकते हैं? http://en.wikipedia.org/wiki/Erase-remove_idiom – msandiford

+0

मिटाएं मिटाएं: http://stackoverflow.com/questions/4175896/safe-way-to-continuously-erase-from-a-stdvector –

उत्तर

31

एक एसटीएल कंटेनर से सभी तत्वों को हटाने का मूर्ख तरीका remove-erase idiom का उपयोग करना है।

static bool pred(const std::string &s) { 
    // ... 
} 

std::vector<std::string> v; 
v.erase(std::remove_if(v.begin(), v.end(), pred), v.end()); 

आप सूचकांकों का उपयोग कर पर जोर देते हैं, तो आप सूचकांक को नहीं बढ़ाया जाना चाहिए: विचार, pred और फिर कहते हैं कि विधेय ले जाने के लिए किसी दिए गए समारोह में (कि समारोह जो कुछ तत्व के लिए सही या गलत पैदावार है) है प्रत्येक तत्व के लिए, लेकिन केवल उन जो हटाया नहीं मिलता था के लिए:

std::vector<std::string>::size_type i = 0; 
while (i < v.size()) { 
    if (shouldBeRemoved(v[i])) { 
     v.erase(v.begin() + i); 
    } else { 
     ++i; 
    } 
} 

बहरहाल, यह न केवल अधिक कोड और कम मुहावरेदार है (पढ़ें: सी ++ प्रोग्रामर वास्तव में कोड को देखने के लिए, जबकि 'मिटा & है हटाएं 'मुहावरे तुरंत कुछ विचार देता है कि क्या हो रहा है), लेकिन बहुत कम कुशल क्योंकि वेक्टर स्टोर वें हैं स्मृति के एक संगत ब्लॉक में ईआईआर तत्व, इसलिए वेक्टर एंड के अलावा अन्य स्थितियों पर मिटाने से सेगमेंट के बाद सभी तत्वों को स्थानांतरित कर दिया जाता है।

+1

v.erase() के बाद आप कितने तत्वों को मार चुके हैं? (पहले और बाद में आकार की गणना किए बिना?) – dynamic

+0

भविष्यवाणी को एक फ़ंक्शन नहीं होना चाहिए, लेकिन एक मज़ेदार हो सकता है (विशेष रूप से यदि आपको यह तय करने के लिए बाहरी डेटा प्राप्त करने की आवश्यकता है कि तत्व को निकालना है या नहीं)। –

+1

@ गतिशील 'std :: vector' में यादृच्छिक-पहुंच इटरेटर्स हैं, इसलिए आप बता सकते हैं कि वर्तमान एंड इटरेटर (जैसे' v.end 'से 'std :: remove_if' द्वारा लौटाए गए नए एंड इटरेटर को घटाकर कितने तत्व मिटा दिए जाते हैं।() ')। –

1

वेक्टर के पीछे पीछे हटना। इस तरह, आप उन तत्वों को प्राप्त करने की क्षमता को नकारते हैं जिन्हें आपने अभी तक नहीं देखा है।

8

का उपयोग करें, remove_if का उपयोग करके अपनी स्थिति निर्दिष्ट करने के लिए एक अनुमान के साथ।

+0

क्या हम रख सकते हैं एसओ के लिए इंटर्न लिंक। यहां बर्बाद होने की संभावना कम है। –

9

आप/मिटा हटाने उपयोग नहीं कर सकते (जैसे क्योंकि आप lambdas का उपयोग करें या एक विधेय लिखने के लिए नहीं करना चाहते हैं), अनुक्रम कंटेनर तत्व हटाने के लिए मानक मुहावरा का उपयोग करें:

for (auto it = v.cbegin(); it != v.cend() /* not hoisted */; /* no increment */) 
{ 
    if (delete_condition) 
    { 
     it = v.erase(it); 
    } 
    else 
    { 
     ++it; 
    } 
} 

यदि संभव हो तो, हालांकि, हटाने पसंद करते/मिटा:

#include <algorithm> 

v.erase(std::remove_if(v.begin(), v.end(), 
         [](T const & x) -> bool { /* decide */ }), 
     v.end()); 
+0

'के लिए (ऑटो इसे ... 'यह संकलन करेगा? – ThomasMcLeod

+0

एक सी ++ 11 कंपाइलर के साथ, हाँ – Vortico

1

मुझे पता है आप वेक्टर से हटाने के बारे में विशेष रूप से कह रहे हैं, लेकिन सिर्फ बाहर बात करने के लिए यह महंगा है कि निकाले गए आइटम के बाद सभी आइटम के बाद से एक एसटीडी से आइटम निकालने की :: वेक्टर चाहता था चाहिए नए स्थान पर कॉपी किया जाना चाहिए। यदि आप कंटेनर से आइटम निकालने जा रहे हैं तो आपको एक std :: सूची का उपयोग करना चाहिए। Std :: list :: मिटाएं (आइटम) विधि किसी भी मिटाने के बाद मान को इंगित करने वाले इटरेटर को भी लौटाती है, इसलिए लूप के लिए या उपयोग में उपयोग करना आसान है। Std :: सूची के साथ भी अच्छी बात यह है कि गैर-मिटाए गए आइटमों को इंगित करने वाले इटरेटर पूरे सूची अस्तित्व में मान्य रहते हैं। उदाहरण के लिए docs at cplusplus.com देखें।

यह कहा गया कि, यदि आपके पास कोई विकल्प नहीं है, तो एक चाल जो काम कर सकती है वह केवल एक नया खाली वेक्टर बनाने और पहले वेक्टर से आइटम जोड़ने के लिए है, फिर std :: swap (oldVec, newVec) का उपयोग करें, जो कि है बहुत कुशल (कोई प्रतिलिपि नहीं, केवल आंतरिक पॉइंटर्स बदलती है)।

3
if(vector_name.empty() == false) { 
    for(int i = vector_name.size() - 1; i >= 0; i--) 
    { 
     if(condition) 
      vector_name.erase(vector_name.at(i)); 
    } 
} 

यह मेरे लिए काम करता है। और इंडेक्स के बारे में सोचने की जरूरत नहीं है पहले से ही मिटा दिया गया है।

+0

मिटाना चाहिए (vector_name.begin() + i); यह भी जांचना चाहिए कि वेक्टर खाली है या नहीं, क्योंकि आकार = = 0 लूप – log0

+0

@ लॉग 0 में कोई पुनरावृत्ति नहीं करेगा @ लॉग 0 यादृच्छिक पहुंच संभव है। क्यों नहीं? और बाद वाले के साथ सहमत हैं। –

+0

'मिटा' एक पुनरावर्तक को तर्क के रूप में लेता है, 'एक' वेक्टर ** मान ** देता है (उदाहरण के लिए एक स्ट्रिंग) – log0

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