remove_if equivalent for std::map

std::map erase
std::remove_if
std map erase
std map erase vs clear
c++ remove_if lambda
no matching function for call to 'remove_if
std map c++ erase
std remove_if algorithm

I was trying to erase a range of elements from map based on particular condition. How do I do it using STL algorithms?

Initially I thought of using remove_if but it is not possible as remove_if does not work for associative container.

Is there any "remove_if" equivalent algorithm which works for map ?

As a simple option, I thought of looping through the map and erase. But is looping through the map and erasing a safe option?(as iterators get invalid after erase)

I used following example:

bool predicate(const std::pair<int,std::string>& x)
{
    return x.first > 2;
}

int main(void) 
{

    std::map<int, std::string> aMap;

    aMap[2] = "two";
    aMap[3] = "three";
    aMap[4] = "four";
    aMap[5] = "five";
    aMap[6] = "six";

//      does not work, an error
//  std::remove_if(aMap.begin(), aMap.end(), predicate);

    std::map<int, std::string>::iterator iter = aMap.begin();
    std::map<int, std::string>::iterator endIter = aMap.end();

    for(; iter != endIter; ++iter)
    {
            if(Some Condition)
            {
                            // is it safe ?
                aMap.erase(iter++);
            }
    }

    return 0;
}

Almost.

for(; iter != endIter; ) {
     if (Some Condition) {
          iter = aMap.erase(iter);
     } else {
          ++iter;
     }
}

What you had originally would increment the iterator twice if you did erase an element from it; you could potentially skip over elements that needed to be erased.

This is a common algorithm I've seen used and documented in many places.

[EDIT] You are correct that iterators are invalidated after an erase, but only iterators referencing the element that is erased, other iterators are still valid. Hence using iter++ in the erase() call.

How to Remove Elements from an Associative Container in C++ , std::map , that has unique keys,; std::multimap , that can have several Removing the elements equivalent to a certain key To remove elements from an sequence container according to a predicate, we used std::remove_if . The similarly-named container member functions list::remove, list::remove_if, forward_list::remove, and forward_list::remove_if erase the removed elements. These algorithms cannot be used with associative containers such as std::set and std::map because ForwardIt does not dereference to a MoveAssignable type (the keys in these containers are

erase_if for std::map (and other containers)

I use the following template for this very thing.

namespace stuff {
  template< typename ContainerT, typename PredicateT >
  void erase_if( ContainerT& items, const PredicateT& predicate ) {
    for( auto it = items.begin(); it != items.end(); ) {
      if( predicate(*it) ) it = items.erase(it);
      else ++it;
    }
  }
}

This won't return anything, but it will remove the items from the std::map.

Usage example:

// 'container' could be a std::map
// 'item_type' is what you might store in your container
using stuff::erase_if;
erase_if(container, []( item_type& item ) {
  return /* insert appropriate test */;
});

Second example (allows you to pass in a test value):

// 'test_value' is value that you might inject into your predicate.
// 'property' is just used to provide a stand-in test
using stuff::erase_if;
int test_value = 4;  // or use whatever appropriate type and value
erase_if(container, [&test_value]( item_type& item ) {
  return item.property < test_value;  // or whatever appropriate test
});

std::experimental::erase_if (std::map , experimental::propagate_const void erase_if(std::map<Key,T,Compare,Alloc>​& c, Pred pred); Equivalent to. for (auto i removeremove_if. Erases all elements that satisfy the predicate pred from the container. Equivalent to

Now, std::experimental::erase_if is available in header <experimental/map>.

See: http://en.cppreference.com/w/cpp/experimental/map/erase_if

std::remove, std::remove_if - cppreference.com, c++ - remove_if equivalent for std::map. I was trying to erase a range of elements from map based on particular condition. How do I do it using STL algorithms? How to Remove Elements from an Associative Container (maps and sets) How to Remove Duplicates from an Associative Container; Associative containers associate keys to values, and they include: std::map, that has unique keys, std::multimap, that can have several equivalent keys, std::unordered_map, the hash map with unique keys,

I got this documentation from the excellent SGI STL reference:

Map has the important property that inserting a new element into a map does not invalidate iterators that point to existing elements. Erasing an element from a map also does not invalidate any iterators, except, of course, for iterators that actually point to the element that is being erased.

So, the iterator you have which is pointing at the element to be erased will of course be invalidated. Do something like this:

if (some condition)
{
  iterator here=iter++;
  aMap.erase(here)
}

c++ - remove_if equivalent for std::map, 'container' could be a std::map // 'item_type' is what you might store in your container using stuff::erase_if; erase_if(container, []( item_type& item ) { return  Transforms the range [first,last) into a range with all the elements for which pred returns true removed, and returns an iterator to the new end of that range. The function cannot alter the properties of the object containing the range of elements (i.e., it cannot alter the size of an array or a container): The removal is done by replacing the elements for which pred returns true by the next

The original code has only one issue:

for(; iter != endIter; ++iter)
{
    if(Some Condition)
    {
        // is it safe ?
        aMap.erase(iter++);
    }
}

Here the iter is incremented once in the for loop and another time in erase, which will probably end up in some infinite loop.

remove_if equivalent for std::map, bool predicate(const std::pair<int,std::string>& x) { return x.first > 2; } int main(void) { std::map<int, std::string> aMap; aMap[2] = "two"; aMap[3] = "three"; aMap[4]  c++ - remove_if equivalent for std::map . I was trying to erase a range of elements from map based on particular condition. How do I do it using STL algorithms? Initially I thought of using remove_if but it is not possible as remove_if does n…

Erase–remove idiom, The erase–remove idiom is a common C++ technique to eliminate elements that fulfill a certain the tail of the array has a length equal to the number of "removed​" items; these items remain in memory std::remove and std::remove_if do not maintain elements that are removed (unlike std::partition , std::stable_partition ). remove_if equivalent pour std :: map J’essayais d’effacer une série d’éléments de la carte en fonction de conditions particulières. Comment puis-je le faire en utilisant les algorithmes STL?

remove_if equivalent for std::map, remove_if equivalent for std::map. Question. I was trying to erase a range of elements from map based on particular condition. How do I do it using STL  The other versions return an iterator to the element that follows the last element removed (or multimap::end, if the last element was removed). Member type iterator is a bidirectional iterator type that points to an element.

std::remove, std::remove_if, The first version removes all elements that are equal to value , the second version Exactly std::distance(first, last) applications of the predicate. be used with associative containers such as std::set and std::map because ForwardIt does not  Erases all elements that satisfy the predicate pred from the container. Equivalent to

Comments
  • What do you mean that remove_if does not work?
  • I can't use remove_if to find an element in map, right? It gave an compile time error. Am I missing something?
  • Nope - it doesn't work as remove_if works by reordering a sequence, moving elements that fail the condition towards the end. Hence it does work on a T[n], but not a map<T,U>.
  • With C+11, you can use for(auto iter=aMap.begin(); iter!=aMap.end(); ){ ....} to reduce clutter. Rest is as others said. This question saved me some hair splitting just now ;-)
  • I'm confused; why would you use for(; ... ;) instead of while(...)? Also, while this probably works, doesn't .erase return an iterator of the next one? So it seems like the if (Some Condition) blog should be iter = aMap.erase(iter) to be the most compatible. Perhaps I'm missing something? I lack the experience some of you have.
  • Note, in C++11 all associative containers, including map, return the next iterator from erase(iter). It's much cleaner to do iter = erase( iter ).
  • @taxilian (years late) while() or for() would work, but semantically, people often use for() for iterating over a known range, and while() for an unknown number of loops. Since the range is known in this case (from the beginning, to endIter), for() wouldn't be an unusual choice, and would probably be more common. But again, both would be acceptable.
  • @taxilian More importantly: with 'for', you can have your iterator definition INSIDE the scope of the loop, so it doesn't mess with the rest of your program.
  • @athos The question is phrased in the passive voice, "it's recommended." There's no universal recommendation. I think my last comment is the most straightforward way. It does involve two copies of the iterator variable, which loses a little efficiency as someone pointed out here. It's your call what's appropriate for you.
  • @CodeAngry Thanks--it always seemed weird to me that this didn't already exist in std. I understand why it isn't a member of std::map, but I think something like it should be in the standard library.
  • Will be added in C++20 for std::map and others.
  • It's now in C++20
  • This is no different to the original code. iter++ increments the iterator then returns an iterator pointing at the element before the increment.
  • But iter will not be invalidated since we then erase at the position of here