erase-remove_if idiom - was anything removed?
Asked Answered
G

3

5

I'm creating an API which users will call to remove items from an internal vector. They will pass in criteria to search the vector for elements to remove. I'd like my API to return a boolean for if any elements were found and removed.

I'm planning on using the erase-remove idiom to keep things simple and efficient. I don't see an obvious way right off to detect that items were actually removed? Is storing the number of elements in the vector before removing, and comparing the value, my best bet?

Here is some (untested) sample code on this idiom:

std::vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

boolean removeMultiples(int multiple) {
    v.erase( std::remove_if(v.begin(), v.end(), [multiple](int i){return i%multiple == 0;}), v.end() );
    // return true if anything was removed
}
Gonick answered 24/5, 2017 at 21:28 Comment(1)
Compare size before and after?Milium
R
9

One idea would be to store the return value of std::remove_if, and compare it with the containers end() iterator before doing the erase like this:

bool removeMultiples(int multiple)
{
    auto it = std::remove_if(v.begin(), v.end(), [multiple](int i){return i%multiple == 0;});
    bool any_change = it != v.end();
    v.erase(it, v.end());
    return any_change;
}
Rainy answered 24/5, 2017 at 21:37 Comment(2)
I would take a lambda instead of hardcoding it. Then have remove multiples call it.Gasket
@Yakk, do you mean the remove_if predicate? If so you're right, and it should probably be a template parameterised on the container type and the predicate, but I just wanted to answer in the questions context.Rainy
A
4

There is no need to write the algorithms in one line. You can for example write

bool removeMultiples( int multiple )
{
    bool success;

    auto it = std::remove_if(v.begin(), v.end(), [multiple](int i){return i%multiple == 0;});

    if ( ( success = it != v.end() ) ) v.erase( it, v.end() );

    return success;
}
Anguilliform answered 24/5, 2017 at 21:38 Comment(0)
G
0
template<class C, class F>
bool remove_some(C&c, F&&f){
  using std::begin; using std::end;
  auto it = std::remove_if(begin(c), end(c), std::forward<F>(f) );
  bool r = it!=end(c);
  c.erase(it, end(c));
  return r;
}

then

bool removeMultiples(std::vector<int>& f, int multiple) {
  return remove_some(v, [multiple](int i){return !(i%multiple);});
}

is simple and clean.

Gasket answered 24/5, 2017 at 22:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.