मैं कैसे सूचकांक से एक तत्व मिटा देता हूं :: वेक्टर <> सूचकांक द्वारा?


508

मेरे पास एक std :: वेक्टर <int> है, और मैं n'th तत्व को हटाना चाहता हूं। मैं उसको कैसे करू?

std::vector<int> vec;

vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);

vec.erase(???);

4
एक std :: deque का उपयोग करने पर विचार करें जो दोनों सिरों को सम्मिलित करता है और हटाता है।
दारियो

40
नहीं, आप केवल एक तत्व को हटाना चाहते हैं, क्योंकि यह वास्तव में खराब सलाह है, क्योंकि आप केवल घटिया उपयोग नहीं करना चाहते हैं। वहाँ कारणों की एक पूरी लोड है कि आप deque या वेक्टर का उपयोग क्यों करना चाहते हैं। यह सच है कि वेक्टर से एक तत्व को हटाना महंगा हो सकता है - अगर वेक्टर बड़ा है, तो esp है, लेकिन यह सोचने का कोई कारण नहीं है कि आपके द्वारा पोस्ट किए गए कोड उदाहरण से एक deque वेक्टर से बेहतर होगा।
उल्लू

6
उदाहरण के लिए, यदि आपके पास एक ग्राफ़िकल एप्लिकेशन है जहाँ आप उन चीजों की "सूची" प्रदर्शित करते हैं जहाँ आप चीजों को सम्मिलित रूप से सम्मिलित / हटाते हैं, तो आप उन्हें प्रदर्शित करने के लिए प्रत्येक सेकंड में 50-100 बार सूची के माध्यम से विचार करें, और आप कुछ चीजों को जोड़ते / हटाते हैं। प्रत्येक मिनट का समय। तो वेक्टर के रूप में "सूची" को लागू करना संभवतः कुल दक्षता की अवधि में एक बेहतर विकल्प है।
माइकल बिल्लौद

जवाबों:


705

किसी एक तत्व को हटाने के लिए, आप यह कर सकते हैं:

std::vector<int> vec;

vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);

// Deletes the second element (vec[1])
vec.erase(vec.begin() + 1);

या, एक से अधिक तत्वों को एक साथ हटाने के लिए:

// Deletes the second through third elements (vec[1], vec[2])
vec.erase(vec.begin() + 1, vec.begin() + 3);

50
यह भी ध्यान रखें द्विआधारी operator+है नहीं जरूरी अन्य कंटेनर प्रकार पर iterators के लिए परिभाषित किया, जैसे list<T>::iterator(आप ऐसा नहीं कर सकते list.begin() + 2एक पर std::list, आप का उपयोग करने के std::advanceलिए है कि)
bobobobo

क्या आप कह रहे हैं कि "+1" पहला तत्व myVector है [0] या वास्तविक स्थिति myVector [1]
कार्ल मॉरिसन

2
अग्रिम के साथ आपको एक चर में पुनरावृत्त को बचाना होगा। यदि आप std का उपयोग करते हैं :: आगे आप इसे एक पंक्ति में कर सकते हैं: vec.erase (अगला (प्रारंभ (vec), 123));
दानी

8
जवाब देने वाले सभी को धन्यवाद। जब हम एक तत्व को हटाने के रूप में इस तरह के एक सरल ऑपरेशन को स्टैकऑवरफ्लो में आने की आवश्यकता होती है, तो हम क्लास डिजाइन के बारे में क्या सोचते हैं?
पियरे

5
@ पियरे क्योंकि किसी विशेष तत्व का संख्यात्मक सूचकांक अभिगम का प्राथमिक मॉडल नहीं है, पुनरावृत्त है। एक कंटेनर के तत्वों को देखने वाले सभी कार्य उस कंटेनर के पुनरावृत्तियों का उपयोग करते हैं। जैसेstd::find_if
कैलथ

212

एसटीडी पर मिटा विधि :: वेक्टर अतिभारित है, इसलिए यह संभवतः कॉल करने के लिए स्पष्ट है

vec.erase(vec.begin() + index);

जब आप केवल एक ही तत्व को मिटाना चाहते हैं।


3
लेकिन यह समस्या आपके पास कितने भी तत्व क्यों न हो, प्रकट होती है।
Zyx 2000

15
यदि केवल एक तत्व है, तो इंडेक्स 0 है, और इसलिए आपको वह मिलता है vec.begin()जो वैध है।
ऐनी क्विन

28
काश किसी ने उल्लेख किया होता जो vec.erase(0)काम नहीं करता, लेकिन vec.erase(vec.begin()+0)(या बिना +0) करता है। अन्यथा मुझे कोई मेलिंग फंक्शन कॉल नहीं मिलता है, यही वजह है कि मैं यहां आया था
qrtLs

@qLLs vec.erase(0)वास्तव में संकलित कर सकता है यदि 0ऐसा होता है कि इसे शून्य सूचक स्थिरांक के रूप में व्याख्यायित किया जाता है ...
LF

57
template <typename T>
void remove(std::vector<T>& vec, size_t pos)
{
    std::vector<T>::iterator it = vec.begin();
    std::advance(it, pos);
    vec.erase(it);
}

2
अधिकतम, जो उस फ़ंक्शन को बेहतर बनाता है: template <typename T> void remove(std::vector<T>& vec, size_t pos) { vec.erase(vec.begin + pos); }मैं या तो बेहतर नहीं कह रहा हूं, केवल व्यक्तिगत हित से बाहर पूछ रहा हूं और सबसे अच्छा परिणाम वापस करने के लिए यह प्रश्न हो सकता है।

13
@JoeyvG: चूंकि एक vector<T>::iteratorरैंडम-एक्सेस इटरेटर है, इसलिए आपका संस्करण ठीक है और शायद थोड़ा साफ है। लेकिन जो संस्करण मैक्स ने पोस्ट किया है वह ठीक काम करना चाहिए यदि आप कंटेनर को दूसरे में बदलते हैं जो रैंडम-एक्सेस पुनरावृत्तियों का समर्थन नहीं करता है
लिली बॉलर

2
यह बेहतर उत्तर है, क्योंकि यह अन्य कंटेनर प्रारूपों पर भी लागू होता है। आप std :: next () का भी उपयोग कर सकते हैं।
बिम

बहुत बेहतर दृष्टिकोण क्योंकि यह कंटेनर के आंतरिक पर भरोसा नहीं करता है।
बार्टोज़केपी

std :: अग्रिम केवल तभी आवश्यक है जब आपको लगता है कि यह एक वेक्टर नहीं होगा अर्थात एक सूची। लेकिन जैसा कि आप यहाँ निर्दिष्ट कर चुके हैं, क्या ऑपरेटर + सरल नहीं होगा? इस stackoverflow.com/questions/1668088/ के अनुसार, ऑपरेटर + के साथ प्रदर्शन में एक संभावित लाभ है
नील बार्बिल

14

eraseविधि को दो तरह से उपयोग किया जाएगा:

  1. एकल तत्व को मिटा देना:

    vector.erase( vector.begin() + 3 ); // Deleting the fourth element
  2. तत्वों की श्रेणी को मिटाना:

    vector.erase( vector.begin() + 3, vector.begin() + 5 ); // Deleting from fourth element to sixth element

7
स्वीकृत उत्तर के लगभग 7 साल बाद यह एक डुप्लिकेट उत्तर है। कृपया ऐसा न करें।
अलास्टेयरग

10

दरअसल, eraseफंक्शन दो प्रोफाइल के लिए काम करता है:

  • किसी एक तत्व को हटाना

    iterator erase (iterator position);
  • तत्वों की एक सीमा को हटाना

    iterator erase (iterator first, iterator last);

चूंकि std :: vec.begin () कंटेनर की शुरुआत को चिह्नित करता है और यदि हम अपने वेक्टर में ith तत्व को हटाना चाहते हैं, तो हम यह कर सकते हैं:

vec.erase(vec.begin() + index);

यदि आप निकट से देखते हैं, तो वेजबिन () हमारे वेक्टर की शुरुआती स्थिति के लिए एक संकेतक है और इसमें i का मान जोड़कर पॉइंटर को i स्थिति में ले जाता है, इसलिए इसके बजाय हम पॉइंटर को ith तत्व तक एक्सेस कर सकते हैं:

&vec[i]

तो हम लिख सकते हैं:

vec.erase(&vec[i]); // To delete the ith element

6
-1 अंतिम पंक्ति संकलित नहीं करती है (कम से कम VS2017 में)। कोड मानता है कि वेक्टर :: पुनरावृत्त स्पष्ट रूप से एक कच्चे पॉइंटर से रचनात्मक है, जो मानक द्वारा आवश्यक नहीं है।
करिश्माईगोर

1
यह विशेष रूप से डिबग इटरेटर के लिए सच है
निशांत सिंह

9

यदि आपके पास एक अनियंत्रित वेक्टर है, तो आप इस तथ्य का लाभ उठा सकते हैं कि यह अनियंत्रित है और CPPCON से डैन हिगिंस से देखी गई किसी चीज़ का उपयोग करें

template< typename TContainer >
static bool EraseFromUnorderedByIndex( TContainer& inContainer, size_t inIndex )
{
    if ( inIndex < inContainer.size() )
    {
        if ( inIndex != inContainer.size() - 1 )
            inContainer[inIndex] = inContainer.back();
        inContainer.pop_back();
        return true;
    }
    return false;
}

चूंकि सूची क्रम कोई मायने नहीं रखता है, बस सूची में अंतिम तत्व लें और उस आइटम के शीर्ष पर प्रतिलिपि करें जिसे आप निकालना चाहते हैं, फिर अंतिम आइटम को पॉप और हटाएं।


मुझे लगता है कि यह सबसे अच्छा जवाब है अगर वेक्टर अनियंत्रित है। यह उस धारणा पर भरोसा नहीं करता है जो iterator + indexवास्तव में आपको उस सूचकांक में पुनरावृत्ति की स्थिति प्रदान करेगा, जो सभी पुनरावृत्त कंटेनरों के लिए सही नहीं है। यह बैक पॉइंटर का लाभ उठाकर रैखिक के बजाय निरंतर जटिलता भी है।
theferrit32

1
इसे पूरी तरह से std lib में जोड़े जाने की आवश्यकता है ... unordered_removeऔर unordered_remove_ifजब तक यह नहीं हुआ है और मुझे यह याद नहीं है, जो इन दिनों अधिक से अधिक बार हो रहा है :)
विल क्रॉफर्ड

अगर कॉपी-असाइनमेंट के बजाय मूव-असाइनमेंट या स्वैप का उपयोग करने का सुझाव देंगे।
कार्स्टन एस

std::removeकंटेनर को फिर से चालू करें ताकि निकाले जाने वाले सभी तत्व अंत में हों, इसे मैन्युअल रूप से करने की आवश्यकता नहीं है यदि आप C ++ 17 का उपयोग कर रहे हैं।
कीथ

@ कैसे std::removeमदद करता है? cppreference का दावा है कि C ++ 17 में भी, सभी removeअधिभार को एक विधेय की आवश्यकता होती है, और कोई भी एक सूचकांक नहीं लेता है।
पॉल डू बोइस

4

यदि आप बड़े वैक्टर (आकार> 100,000) के साथ काम करते हैं और बहुत सारे तत्वों को हटाना चाहते हैं, तो मैं इस तरह से कुछ करने की सलाह दूंगा:

int main(int argc, char** argv) {

    vector <int> vec;
    vector <int> vec2;

    for (int i = 0; i < 20000000; i++){
        vec.push_back(i);}

    for (int i = 0; i < vec.size(); i++)
    {
        if(vec.at(i) %3 != 0)
            vec2.push_back(i);
    }

    vec = vec2;
    cout << vec.size() << endl;
}

कोड vec में प्रत्येक संख्या लेता है जिसे 3 से विभाजित नहीं किया जा सकता है और इसे vec2 में कॉपी कर सकता है। बाद में यह vec में vec2 को कॉपी करता है। यह बहुत तेज है। 20,000,000 तत्वों को संसाधित करने के लिए यह एल्गोरिथ्म केवल 0.8 सेकंड लेता है!

मैंने इरेज़-मेथड के साथ एक ही काम किया, और इसमें बहुत सारे और बहुत समय लगता है:

Erase-Version (10k elements)  : 0.04 sec
Erase-Version (100k elements) : 0.6  sec
Erase-Version (1000k elements): 56   sec
Erase-Version (10000k elements): ...still calculating (>30 min)

6
इस सवाल का जवाब कैसे देता है?
रेजिस पोर्टालेज़

4
दिलचस्प है, लेकिन सवाल के लिए प्रासंगिक नहीं है!
रोडी

एक जगह एल्गोरिथ्म तेजी से नहीं होगा?
user202729

2
कि std :: remove_if (+
erase

3

किसी तत्व को हटाने के लिए निम्न तरीके का उपयोग करें:

// declaring and assigning array1 
std:vector<int> array1 {0,2,3,4};

// erasing the value in the array
array1.erase(array1.begin()+n);

एक के लिए और अधिक विस्तृत अवलोकन आप यात्रा कर सकते हैं: http://www.cplusplus.com/reference/vector/vector/erase/


Cppreference का उपयोग करने पर विचार करें । यह , यह , आदि देखें ।
वामो

3

मैं इसे पढ़ने का सुझाव देता हूं क्योंकि मेरा मानना ​​है कि आप वही चाहते हैं जो आप खोज रहे हैं। https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom

यदि आप उदाहरण के लिए उपयोग करते हैं

 vec.erase(vec.begin() + 1, vec.begin() + 3);

आप वेक्टर के n -th तत्व को मिटा देंगे, लेकिन जब आप दूसरे तत्व को मिटा देंगे, तो वेक्टर के अन्य सभी तत्व स्थानांतरित हो जाएंगे और वेक्टर का आकार -1 हो जाएगा। यह समस्या हो सकती है यदि आप वेक्टर के माध्यम से लूप करते हैं क्योंकि वेक्टर आकार () कम हो रहा है। यदि आपके पास इस तरह की समस्या है, तो मानक C ++ लाइब्रेरी में मौजूदा एल्गोरिदम का उपयोग करने के लिए दिए गए लिंक का सुझाव दिया गया है। और "हटाएं" या "remove_if"।

उम्मीद है कि इससे मदद मिली


0

पिछले उत्तर मान लेते हैं कि आपके पास हमेशा एक हस्ताक्षरित सूचकांक है। अफसोस की बात है, अनुक्रमण के लिए std::vectorउपयोग करता size_typeहै, औरdifference_type इटरेटर अंकगणित के लिए, इसलिए वे एक साथ काम नहीं करते हैं यदि आपके पास "-Wconversion" और मित्र सक्षम हैं। यह हस्ताक्षरित और अहस्ताक्षरित दोनों को संभालने में सक्षम होते हुए, सवाल का जवाब देने का एक और तरीका है:

दूर करना:

template<class T, class I, class = typename std::enable_if<std::is_integral<I>::value>::type>
void remove(std::vector<T> &v, I index)
{
    const auto &iter = v.cbegin() + gsl::narrow_cast<typename std::vector<T>::difference_type>(index);
    v.erase(iter);
}

लेना:

template<class T, class I, class = typename std::enable_if<std::is_integral<I>::value>::type>
T take(std::vector<T> &v, I index)
{
    const auto &iter = v.cbegin() + gsl::narrow_cast<typename std::vector<T>::difference_type>(index);

    auto val = *iter;
    v.erase(iter);

    return val;
}

0

यहाँ ऐसा करने का एक और तरीका है यदि आप वेक्टर में इसके मान के साथ किसी तत्व को हटाना चाहते हैं, तो आपको बस वेक्टर पर ऐसा करने की आवश्यकता है।

vector<int> ar(n);
ar.erase(remove(ar.begin(), ar.end()), (place your value here from vector array));

यह आपके मूल्य को यहां से हटा देगा। धन्यवाद


0

इस बारे में कैसा है?

void squeeze(vector<int> &v)
{
    int j = 0;
    for (int i = 1; i < v.size(); i++)
        if (v[i] != v[j] && ++j != i)
            v[j] = v[i];
    v.resize(j + 1);
}

-4

सबसे तेज तरीका (समय की जटिलता से प्रोग्रामिंग प्रतियोगिता के लिए) = स्थिर)

1 सेकंड में 100M आइटम मिटा सकते हैं;

    vector<int> it = (vector<int>::iterator) &vec[pos];
    vec.erase(it);

और सबसे पठनीय तरीका: vec.erase(vec.begin() + pos);


2
यह बहुत गैर-पोर्टेबल है; यह libstdc ++ के साथ काम करेगा, लेकिन libc ++ के साथ नहीं, और MSVC के साथ नहीं। vector<int>::iteratorजरूरी नहीं है किint *
मार्शल क्लो

2
यह घृणित है, मुझे लगता है कि मैं इसे काम करने से रोकने के लिए libstdc ++ को बदल दूंगा।
जोनाथन वेकली
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.