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()
.
精彩评论