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?
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).