Map: Löschen aller Elemente mit einem bestimmten Wert (nicht Key)



  • ich frage mich gerade wie man in einer map alle Elemente löschen kann, die einen bestimmten Wert haben - z. B. hab ich ein Englisch-Deutsch-Wörterbuch wobei der Key das Englische Wort ist und der Wert die deutsche Entsprechung. Nimmt man dazu einen Iterator und huscht über alle Elemente drüber oder kann man das schöner machen - ich denke das dies ein häufiger Anwendungsfall ist und es da doch was fertiges geben muss (vielleicht gibt es auch eine bessere Containerklasse für mein Problem)

    class Dictionary
    {
    public:
    	void insert(string english, string german)
    	{
    		m_Dictionary.insert(map<string,string>::value_type(english,german));
    	}
    
    	string translate(string english)
    	{
    		return m_Dictionary[english];
    	}
    
    	void deleteEnglish(string english)
    	{
    		m_Dictionary.erase(english);
    	}
    
    	void deleteGerman(string german)
    	{
    		map<string,string>::iterator i = m_Dictionary.begin();
    		while(i != m_Dictionary.end())
    		{
    			if(i->second == german)
    			{
    				i = m_Dictionary.erase(i);
    			}
    			else
    				i++;
    		}
    	}
    
    	bool contains(string english)
    	{
    		map<string,string>::iterator i = m_Dictionary.find(english);
    
    		return (i != m_Dictionary.end());
    	}
    
    	bool isEmpty()
    	{
    		return m_Dictionary.empty();
    	}
    private:
    	map<string,string> m_Dictionary;
    };
    
    int main()
    {
    	Dictionary map;
    
    	if(map.isEmpty())
    		cout<<"ist leer"<<endl;
    
    	map.insert("go","gehen");
    	map.insert("to go", "gehen");
    
    	if(!map.isEmpty())
    		cout<<"ist nicht leer"<<endl;
    
    	if(map.contains("to go"))
    		cout<<"wort gefunden!"<<endl;
    	else
    		cout<<"Wort nicht gefunden!"<<endl;
    
    	cout<<map.translate("to go")<<endl;
    
    	map.deleteGerman("gehen");
    
    	if(map.isEmpty())
    		cout<<"ist leer"<<endl;
    
    }
    

  • Mod

    mit einer einfachen map wird dir nichts anderes übrigbleiben, als den gesamten container zu unteruchen. übrigens liefert map< >::erase keinen iterator zurück, folglich muss es

    if(i->second == german)
                {
                    m_Dictionary.erase(i++);
                }
                else
                    ++i;
    

    heißen.

    für diesen fall wäre eine bidirektionale map (oder eher noch multimap) nützlich - boosts multi_index_container ist dafür gut geeignet.



  • Wieso verwendest du std::string, wenn du eine Sprache verwendest bei der der ASCII-Zeichensatz nicht ausreicht? Verwende std::wstring



  • Lolz schrieb:

    Wieso verwendest du std::string, wenn du eine Sprache verwendest bei der der ASCII-Zeichensatz nicht ausreicht? Verwende std::wstring

    ich hab ja nicht ernsthaft vor eine Wörterbuch zu programmieren - es ist eine Abbildung von Window Handles zu entsprechenden Control Klassen die über einen WindowManager laufen - ich hab das einfach mal hier auf das Grundlegende Problem beschränkt - wstring ist mir durchaus bekannt

    übrigens liefert map< >::erase keinen iterator zurück,

    toll, das der Compiler nicht drüber mekert... ich dachte, wenn ich das Element lösche, dann rutschen die darunterliegenden Elemente eines hoch - d. h. ich dachte ich zeig dann schon auf das nächste Elemente bzw. hab gehoft die erase Funktion liefert mir einen Iterator auf das nächste Element

    Ich verstehe die Anweisung jetzt nicht - der Iterator zeigt ja auf das zu löschende Element - anschießend wird das Element, auf der er zeigt ja gelöscht - zeigt er jetzt immer noch auf das Element das soeben gelöscht wurde - wenn ich jetzt postincrement mache, dann mache ich das ja auf einen Iterator, der momentan ins Nirvana zeigt... mmh...



  • Vertexwahn schrieb:

    Ich verstehe die Anweisung jetzt nicht - der Iterator zeigt ja auf das zu löschende Element - anschießend wird das Element, auf der er zeigt ja gelöscht - zeigt er jetzt immer noch auf das Element das soeben gelöscht wurde - wenn ich jetzt postincrement mache, dann mache ich das ja auf einen Iterator, der momentan ins Nirvana zeigt... mmh...

    Der Iterator selber zeigt noch auf den selben Speicherplatz, der aber nach dem erase() ungültig ist. Der Trick bei der Anweisung ist, daß der Postinkrement Operator zwar den Iterator weiterschiebt, aber den alten Wert zurückgibt (d.h. dein Iterator rutscht auf's nächste Map-Element, bevor das aktuelle gelöscht wird).



  • 💡 danke - ich dachte bisher, dass der Compiler das in etwas so umformt:

    iterator i = x.begin();
    x.erase(i++);
    

    wird zu

    iterator i = x.begin();
    x.erase(i);
    i = i + 1;
    

    und nicht zu:

    iterator i = x.begin();
    iterator tmp = i+1;
    x.erase(i);
    i = tmp;
    

Anmelden zum Antworten