call a function, inside a for loop, to remove elements in a vector (or list)

368 Views Asked by At
vector<node>::iterator it;
for(it;it!=vector_of_node.end();it++){
    if(it->get_name()=="MARIA"){
        vector_of_node.erase(it);
}

i hope the goal of my code is clear. i want to eliminate multiple objects (which are described in a class called node) from a vector (vector_of_nodes in this case). when i run my code i don't get any error from the compliler but i got a fail while it's running. i'm sure that the error is on this portion of code that i've shared. can you hel me?

3

There are 3 best solutions below

6
On BEST ANSWER

Erasing while iterating is possible if you increment the iterator inside the loop depending on if you erase the element or not. If you erase it, the erase method returns the next iterator in the vector, if not, increment it yourself. Moreover, you need to initialize the iterator to begin.

vector<node>::iterator it;
for(it=vector_of_node.begin();it!=vector_of_node.end();){
    if(it->get_name()=="MARIA")
        it = vector_of_node.erase(it);
    else
        ++it;
}
0
On

With your current approach, i.e., erasing elements in the vector one by one, all the elements after the erased one have to be moved to the front of the vector. This is done for every iteration that erases an element (no movement of elements only if you erase the back of the vector).

As an alternative, you may want to consider the Erase-remove idiom. It is better suited if you intend to remove multiple elements from an std::vector.

// predicate (C++14 for generic lambda)
auto is_maria = [](auto elem) {
   return elem.get_name() == "MARIA";
};  

auto end = std::remove_if(vector_of_node.begin(), vector_of_node.end(), is_maria); 
vector_of_node.erase(end, vector_of_node.end());

The idea is to leave the elements you want to erase at the back of the vector and then remove then from the vector with a single erase() call to the corresponding overload that takes a range (i.e., an iterator pair).

0
On

Eliminating multiple objects in a vector by erasing one at a time is very inefficient. Each erase call will shuffle all elements on the right by one position. There is already a standard library pattern to do this better, using std::remove:

std::erase(std::remove_if(vector_of_node.begin(),
                          vector_of_node.end(),
                          [](const node& n) { return n->get_name() == "MARIA"; }),
           vector_of_node.end());

The result of std::remove_if is the vector rearranged with all matches moved to the end, and it returns an iterator to the first of the matches. You then call std::erase to remove them all.