tags:

views:

3389

answers:

5

I want to clear a element from a vector using the erase method. But the problem here is that the element is not guaranteed to occur only once in the vector. It may be present multiple times and I need to clear all of them. My code is something like this:

void erase(std::vector<int>& myNumbers_in, int number_in)
    {
        std::vector<int>::iterator iter = myNumbers_in.begin();
        std::vector<int>::iterator endIter = myNumbers_in.end();
        for(; iter != endIter; ++iter)
        {
         if(*iter == number_in)
         {
          myNumbers_in.erase(iter);
         }
        }

    }


    int main(int argc, char* argv[])
    {
        std::vector<int> myNmbers;
        for(int i = 0; i < 2; ++i)
        {
         myNmbers.push_back(i);
         myNmbers.push_back(i);
        }

        erase(myNmbers, 1);


        return 0;
    }

This code obviously crashes because I am changing the end of the vector while iterating through it. What is the best way to achieve this ? i.e. is there any way to do this without iterating through the vector multiple times or creating one more copy of the vector?

A: 

You could start from the end or update the end when an element is erased.

It would look something like this:

void erase(std::vector<int>& myNumbers_in, int number_in)
    {
        std::vector<int>::iterator iter = myNumbers_in.begin();
        std::vector<int>::iterator endIter = myNumbers_in.end();
        for(; iter != endIter; ++iter)
        {
                if(*iter == number_in)
                {
                        myNumbers_in.erase(iter);
                        endIter = myNumbers_in.end();
                }
        }

    }
Burkhard
I tried the above piece of code. It worked for my initial case, but when I created a vector with 0,0,0,1 as the values and tried to erase 0 it didn't work properly. After exiting the loop I found that the size of the vector is 2 instead of 1.
Naveen
This is worst-case O(N^2). O(N) algorithms exist. You can do better. Also, erase(iter) followed by ++iter may, depending on the STL vector<> implementation, skip the following entry. Consider "erase v[i=2]; i++;" -- you never check the original i=3 (now i=2) entry in v[].
Mr.Ree
+6  A: 

Calling erase will invalidate iterators, you could use:

void erase(std::vector<int>& myNumbers_in, int number_in)
{
    std::vector<int>::iterator iter = myNumbers_in.begin();
    while (iter != myNumbers_in.end())
    {
        if (*iter == number_in)
        {
            iter = myNumbers_in.erase(iter);
        }
        else
        {
           ++iter;
        }
    }

}

Or you could use std::remove_if together with a functor and std::vector::erase:

struct Eraser
{
    Eraser(int number_in) : number_in(number_in) {}
    int number_in;
    bool operator()(int i) const
    {
        return i == number_in;
    }
};

std::vector<int> myNumbers;
myNumbers.erase(std::remove_if(myNumbers.begin(), myNumbers.end(), Eraser(number_in)), myNumbers.end());

Instead of writing your own functor in this case you could use std::remove:

std::vector<int> myNumbers;
myNumbers.erase(std::remove(myNumbers.begin(), myNumbers.end(), number_in), myNumbers.end());
dalle
Why use your own functor when you can use equal_to? :-P http://www.sgi.com/tech/stl/equal_to.html
Chris Jester-Young
By the way, calling `erase` with `remove` is the canonical way to do this.
Konrad Rudolph
i thinkhe does exactly that. but he should use remove_if if using an own functor iirc. or just use remove without the functor
Johannes Schaub - litb
+19  A: 

Use the remove/erase idiom:

std::vector<int>& vec = myNumbers; // use shorter name
vec.erase(vec.remove(vec.begin(), vec.end(), number_in), vec.end());

What happens is that remove moves all the elements to the end of the vector and returns the iterator to the first element erased. Then erase removes them.

Motti
+1  A: 

Depending on why you are doing this, using a std::set might be a better idea than std::vector.

It allows each element to occur only once. If you add it multiple times, there will only be one instance to erase anyway. This will make the erase operation trivial. The erase operation will also have lower time complexity than on the vector, however, adding elements is slower on the set so it might not be much of an advantage.

This of course won't work if you are interested in how many times an element has been added to your vector or the order the elements were added.

Laserallan
+4  A: 
sergdev