开发者

Erasing the last element of a vector by looping through it

I want to loop through a vector and erase certain elements that correspond to a certain criteria, for example:

vector<int> myvector;
vector<int>::iterator it;

myvector.开发者_JS百科push_back(1);
myvector.push_back(2);
myvector.push_back(3);
myvector.push_back(4);

for(it = myvector.begin(); it != myvector.end(); ++it){

    if((*it) == 4){
        it = myvector.erase(it);
    }
}

Now this works fine unless the criterion erases the last item like in the code above. How do you avoid this behaviour ?

Thanks.

EDIT------------------------------------

Now the reason I was looping through it was that there are actually 4 vectors I need to delete the element from (but the criterion is only on one vector):

In this case, is this how to go ?

vector<int> myvector;
vector<int> myvector2;
vector<int> myvector3;
vector<int> myvector4;
vector<int>::iterator it;
vector<int>::iterator it2;
vector<int>::iterator it3;
vector<int>::iterator it4;

myvector.push_back(1);
myvector.push_back(2);
myvector.push_back(3);
myvector.push_back(4);

(assume myvector2/3/4 have values inside them)

it2 = myvector2.begin()
it3 = myvector3.begin()
it4 = myvector4.begin()

for(it = myvector.begin(); it != myvector.end();){

    if((*it) == 4){
        it = myvector.erase(it);
        it2 = myvector2.erase(it2);
        it3 = myvector3.erase(it3);
        it4 = myvector4.erase(it4);
    }
    else{
    ++it;
    ++it2;
    ++it3;
    ++it4;
    }
}

Is there a modification to the erase/remove idiom valid in this case ?


The usual is the remove/erase idiom, which would look something like this:

myvector.erase(std::remove(myvector.begin(), myvector.end(), 4), myvector.end());

Edit: Rereading your question, you mention "certain criteria". If the criteria aren't necessarily just removing a single value, you can use std::remove_if instead of std::remove, and specify your criteria in a functor.

Edit2: for the version dealing with four vectors, the usual method is to create a struct holding the four related values, and delete entire structs:

struct x4 { 
    int a, b, c, d;

    // define equality based on the key field:
    bool operator==(x4 const &other) { return a == other.a; }

    x4(int a_, int b_=0, int c_=0, ind d_=0) : a(a_), b(b_), c(c_), d(d_) {}
};

std::vector<x4> myvector;

myvector.erase(std::remove(myvector.begin(), myvector.end(), x4(4));

Again, if your criteria are more complex than you can easily express in a comparison operator, you can use std::remove_if instead of std::remove. This is also useful if/when you might need to apply different criteria at different times.

If you really need to keep your data in parallel vectors (e.g., you're feeding the data to something external that requires separate, contiguous arrays), then using a loop is probably as good as the alternatives.


Don't do this with a for loop, there's already a well-debugged algorithm for you.

myvector.erase(std::remove(myvector.begin(), myvector.end(), 4), myvector.end());


I think you should write the loop as :

for(it = myvector.begin(); it != myvector.end(); )
{
    if((*it) == 4)
        it = myvector.erase(it);
    else
        ++it; //increment here!
}

Because in your code, if you find 4, you update it in the if block itself, but after that you again increment/update it in the for also which is wrong. That is why I moved it to else block that ensures that it gets incremented if you don't find 4 (or whatever value you're searching).

Also remember that erase returns iterator pointing to the new location of the element that followed the last element erased by the function call.


erase is generally used with remove (Also have a look at erase-remove idiom) as shown below

myvector.erase(std::remove(myvector.begin(), myvector.end(), 4), myvector.end());


for(it = myvector.begin(); it < myvector.end(); ++it){

    if((*it) == 4){
        it = myvector.erase(it);
    }
}

This will make sure your loop will break if the it >= myvector.end().

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜