Elemente einer std::map anhand eines Prädikats löschen



  • Hi,
    ich will bestimmte Elemente einer std::map anhand eines Prädikats löschen. Allerdings habe ich mit dem eigentlichen löschen ein Problem. Jedes erase könnte ja den Suchbaum neu ausbalancieren. Wenn ich nun mit einer for-Schleife und dem begin-Iterator über alle Elemente gehe, wird doch der Iterator, den mir begin(map) geliefert hat, ungültig, sobald ich 1x erase mache, oder? Brauch ich dann immer wieder einen neuen begin-Iterator?

    Hier mal ein Beispiel. Ich zähle, wie oft ein Buchstabe in einem Satz vorkommt. Alle Buchstaben, die nur 1x vorkommen, will ich dann löschen:

    #include <cctype>
    #include <iterator>
    #include <map>
    #include <string>
    using namespace std;
    
    struct map_erase_predicate
    {
    	unsigned min;
    	map_erase_predicate( unsigned min ) : min(min) {}
    	bool operator()    ( const pair<char,unsigned>& p ) const { return p.second<min; }
    };
    
    void map_erase_elements( map<char,unsigned>& m, const map_erase_predicate& p )
    {
    	for(auto it=begin(m); it!=end(m); ++it) // Wie muss die for-Schleife aussehen?
    	{
    		if( p(*it) )
    		{
    			m.erase( it );
    		}
    	}
    }
    
    int main()
    {
    	string sentence = "stanleys expeditionszug quer durch afrika wird von jedermann bewundert";
    
    	map<char,unsigned> count_letters;
    
    	for(auto c : sentence)
    	{
    		if( isalpha(c) )
    			++count_letters[c];
    	}
    
    	map_erase_elements( count_letters, map_erase_predicate(2) );
    }
    

    Die for-Schleife funktioniert so ja nicht. Wie müsste sie aussehen?

    Danke im Voraus.



  • Hallo,

    s. http://stackoverflow.com/questions/263945/what-happens-if-you-call-erase-on-a-map-element-while-iterating-from-begin-to

    Durch den erase-Aufruf wird der Iterator ungültig, und daher muß man vorher inkrementieren, um einen Iterator auf das nächste Element zu erhalten.

    Aber ab C++11 liefert erase einen Iterator zurück, s. http://www.cplusplus.com/reference/map/map/erase/



  • for (auto it = m.begin(); it != m.end(); ) // so muss die for-Schleife aussehen 
        if (p(*it))
            m.erase(it++);
        else
            it++;
    


  • Th69 schrieb:

    http://stackoverflow.com/questions/263945/what-happens-if-you-call-erase-on-a-map-element-while-iterating-from-begin-to

    Erasing elements in a map does not invalidate any iterators. (apart from iterators on the element that was deleted.

    Ok, dann hatte ich das irgendwie falsch im Kopf. Danke euch. 🙂



  • Wie wärs mit erase und remove_if?

    m.erase(remove_if(begin(m), end(m), PREDICATE), end(m));
    


  • Skym0sh0 schrieb:

    Wie wärs mit erase und remove_if?

    m.erase(remove_if(begin(m), end(m), PREDICATE), end(m));
    

    std::remove_if geht nicht mit assoziativen Containern.


Log in to reply