Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using erase-remove_if idiom

Let's say I have std::vector<std::pair<int,Direction>>.

I am trying to use erase-remove_if idiom to remove pairs from the vector.

stopPoints.erase(std::remove_if(stopPoints.begin(),
                                stopPoints.end(),
                                [&](const stopPointPair stopPoint)-> bool { return stopPoint.first == 4; }));

I want to delete all pairs that have .first value set to 4.

In my example I have pairs:

- 4, Up
- 4, Down
- 2, Up
- 6, Up

However, after I execute erase-remove_if, I am left with:

- 2, Up
- 6, Up
- 6, Up

What am I doing wrong here?

like image 522
omegasbk Avatar asked Aug 18 '16 13:08

omegasbk


People also ask

What is the difference between erase and clear?

clear() removes all elements from the vector leaving behind a vector of size zero while erase() deletes a single element or a range of elements from the vector.

How does STD remover work?

std::remove : It doesn't actually delete elements from the container but only shunts non-deleted elements forwards on top of deleted elements. vector::erase : Removes from the vector either a single element (position) or a range of elements ([first, last)).


1 Answers

The correct code is:

stopPoints.erase(std::remove_if(stopPoints.begin(),
                                stopPoints.end(),
                                [&](const stopPointPair stopPoint)-> bool 
                                       { return stopPoint.first == 4; }), 
                 stopPoints.end());

You need to remove the range starting from the iterator returned from std::remove_if to the end of the vector, not only a single element.

"Why?"

  • std::remove_if swaps elements inside the vector in order to put all elements that do not match the predicate towards the beginning of the container. This means that if the predicate (body of the lambda function) returns true, then that element will be placed at the end of the vector.

  • remove_if then **returns an iterator which points to the first element which matches the predicate **. In other words, an iterator to the first element to be removed.

  • std::vector::erase erases the range starting from the returned iterator to the end of the vector, such that all elements that match the predicate are removed.


More information: Erase-remove idiom (Wikipedia).

like image 195
Vittorio Romeo Avatar answered Oct 02 '22 05:10

Vittorio Romeo