stl map key löschen
-
Hallo
ich habe ein Problem
Ich habe eine STLMap die besteht aus CString( als key ) und eine weitere map als Value. wenn ich jetzt einen bestimmten Key in der zweiten map löschen will, wie mache ich das?
std::map<CString,MyType*>::iterator p; // MyType ist eine map p = sectionKeys_.find(key); // finde key if(p != sectionKeys_.end() ){ // wenn gefunden MyType::iterator kc; kc = p->second->begin(); // setze auf anfang while ( kc != p->second->end() ) // gehe alle key's in der 2ten map durch { if( kc->second == m_meinsuchwert ) // wenn wert gefunden { sectionKeys_.erase(kc->first); // <-- problem } ++kc; }
Eigentlich heisst es ja
MyMap.erase("wert");
oder
MyMap.erase(MyIt); Aber ich müsste ja hinschreibensectionKeys_.erase(p->second.find(kc->first)); //oder Sql like sectionKeys_.erase(p->second.WHERE(kc->first);
-
while ( kc != p->second->end() ) // gehe alle key's in der 2ten map durch
{if( kc->second == m_meinsuchwert ) // wenn wert gefunden
{sectionKeys_.erase(kc++); // <-- problem
}
else
++kc;}
Wenn du allerdings eine Map nach ihren Werten und nicht nach ihren Schlüsseln durchsuchst, frage ich mich, wozu du überhaupt eine Map hast?
-
geht nicht, da
error C2664 kommt
class A {} a;
func( int, A );
void main()
{
func( 1, 1 ); // error, no conversion from int to A
}Warum? ich habe eine map mit
Keys und Values
der Key darf nur einmal vorkommen. jetzt hab ich eine art flag wenn das flag erfüllt ist, brauch ich den key nicht und er wird gelöscht. also ich habe einen Key mit Value( dieser Value hat ein flag )
-
Wenn du so Aktionen öfter brauchst lohnt es sich evtl. zusätzlich zur MyType-Map eine multimap (MyType::value -> MyType::key) anzulegen, das ganze ggf zu wrappen.
-
sectionKeys_.erase(kc++); // <-- problem
}
else
++kc;}
kann das so klappen?
auf jeden fall ich habs jetzt
std::map<CString,MyType*>::iterator p; // MyType ist eine map p = sectionKeys_.find(key); // finde key if(p != sectionKeys_.end() ){ // wenn gefunden //***************** MyType *p1 = p->second; // hier ZEIGER auf map :) //***************** MyType::iterator kc; kc = p->second->begin(); // setze auf anfang while ( kc != p->second->end() ) // gehe alle key's in der 2ten map durch { if( kc->second == m_meinsuchwert ) // wenn wert gefunden { CString copy = kc->first; kc++; // zeige auf nächsten p1->erase(copy); // lösche // lösche von mapzeiger } ++kc; }
cool, oder?
-
maplover schrieb:
cool, oder?
Kommt auf die Sichtweise drauf an. Eine Methode die je nach Lust und Laune - lies "je nach Datenlage" - entweder funktioniert oder bis zu der Hälfte der vorkommenden Suchwerte ignoriert hat schon was.
(Tipp: pro Schleifendurchlauf kc nur einmal erhöhen; dann bist du ungefähr bei der Lösung die kwaart vorgeschlagen hat
)
-
wie meinst du das?
kannst mir ein beispiel nennen in dem es bei mir nicht klappt?
danke
-
maplover schrieb:
wie meinst du das?
kannst mir ein beispiel nennen in dem es bei mir nicht klappt?
dankeBastel dir selber eins
(Tipp: füge zwei mal den Suchwert ein für Keys die aufeinander folgen
)
-
(Tipp: füge zwei mal den Suchwert ein für Keys die aufeinander folgen
)
Ich würd an deiner stelle stl map nochmals durcharbeiten
ne map kann keinen doppelten key eintrag haben, per definition schon. deshalb kann ich gar keinen key 2 mal einfügen
ist keine multimap. deshalb kann ich einfach nach dem key suchen und ihn als wert löschenich habe gerade die map schon getestet. key einfügen, löschen, mehrere löschen ( letzte/erste ) alle löschen usw.
und die map passte immer, weiss jetzt wirklich nicht warum nur in den hälften der fälle lieber @finix
-
Eine Map kann aber zweimal denselben Wert (value) speichern. Und du suchst ja hier nach dem Wert (deswegen auch meine Frage, wozu du eigentlich diese Map hast
).
Und wenn jetzt zweimal derselbe Wert hintereinander auftritt (mit unterschiedlichen Keys), der deinem Suchkriterium entspricht, dann wird der erste gelöscht, der zweite jedoch nicht, weil du den Iterator zweimal erhöhst.Mein Vorschlag sollte eigentlich schon richtig sein.
-
Du musst meinen code genauer anschauen!
Ich habe eine map mit (CString,map2) // key_1 + map2(key_2 + int_value)
in der map2 hab ich (CString,int)
jetzt suche ich den Key_1 in der "map1" )
wenn der key gefunden ist, dann gehe ich die map 2 durch. ich benutze einen ITerator der die map durchgeht und auf das entsprechende objekt zeigt. wenn das objekt den int wert ( z.b. int_value == 255 ), dann lösche ich DIESES objekt wo der ITerator MOMENTAN drauf zeigt. ich sagte nicht "guck map durch und bei dem wert(value) lösche )
sondern ich lösche in der map den key wo der ITERATOR gerade just in diesem moment zeigt. und wenn da der wert zu dem key den wert xyz hat, dann lösche ich DIESE stelle eben und schaue dann den nächsten key ob der den wert xyz hat.
alles verstanden? ich denke nicht. aber macht ja nicht, ist nicht dein projekt
-
für was das gut ist?
hier z.b. ein .ini file
[blub1] key1=value key2=value .. .. [blub2] key1=asdfa key123=qwe5 ... ..
Jetzt lese ich das ini file ein. und dann kann ich die verschienden key bearbeiten. diese zeige ich an. bei änderungen löschungen ect bekommen die eine andere farbe in meiner gui. am schluss nachdem ich fertig bin, kann ich das ini file ( oder die daten aus der db ) wieder schreiben und da schaue ich nach.
wenn z.b. blub1 das flag( die farbe ) gelöscht hat ( z.b. rot ) dann lösche aus db.
bei farbe rot z.b. bei blub2 der key123 dann lösche diesen. ich habe eine spezielle datenstruktur dieblub + alle key von blub + alle value von blub + farbe von blub + farbe von key beinhaltet. Ich möchte nach allen operationen erst am schluss in DB oder file schreiben.
und warum soll da eine map schlecht sein bitte?
-
Es tut mir leid, aber du bist es, der nicht versteht, fürchte ich
Mir ist schon klar, dass du die innere Map mit dem Iterator durchsuchst. ABER: Du durchsuchst sie nach dem WERT, nämlich dem int. Und das ist nicht unbedingt das, was man mit einer Map macht
Was nicht heißt, dass es nicht durchaus ok sein, aber deswegen habe ich nach der Verwendung der Map gefragt.
Trotzdem, wenn du es tun willst, solltest du meinen Code verwenden, er tut nämlich genau das, was du willst: Er löscht bei Übereinstimmung des Wertes mit deinem Parameter das Element, auf das dein Iterator momentan zeigt, erhöht aber gleichzeitig den Iterator (wodurch er seine Gültigkeit behält). Und nur, falls der Wert deinem Kriterium nicht entspricht, wird der Iterator sonst erhöht.
Dein Code tut das folgende: Wenn das momentane Element deinem Kriterium entspricht, dann erstellst du eine Kopie des Iterators und erhöhst kc. Dann löschst du das Element, auf das die Kopie zeigt. Bis hierhin ist das mit meinem Code identisch, außer, dass ich es kompakter geschrieben habe
Aber: Nun verlässt dein Code die Bedingungsschleife und erhöht kc nochmal! Damit überspringst du ein Element, das nun nie geprüft wird. Geh das mal im Kopf durch, es ist wirklich so
-
sorry wenn ich doch falsch liege. aber es passt so bei mir. die werte die ich ein und aus lese stimmen. ich lade die key und values ein von einer anderen datenstruktur und in meiner "map" habe ich nur key+farbe gespeichert. wenn ich da nicht korekt lösche oder einfüge hängt es ja. da ich ja sage
schreibe key/value in box
suche jetzt key in map 2 wenn gefunden dann hat die zeile die farbe von int wenn nicht zeige schwarz an. in meiner box kommt schwarz nie vor. also müsste alles passenwo erstelle ich nach dem suchkriterium eine kopie?
ich weise nur einem CString zu und erhöhe und lösche dann.kannst mir das nochmal hinschreiben? denn vielleicht hast du nicht gesehen, dass dein code nicht geht, wegen dem Error! Also, so wie du es hingeschrieben hast, compiliert er nicht, deswegen kann ich auch nicht testen.
-
Ok, stell dir vor, du hast eine deiner inneren Maps (map2) mit folgenden Inhalten:
key1 -> 1
key2 -> 2
key3 -> 2
key4 -> 15Das ist also die Map, auf die dein iterator p (bzw. pointer p1) gerade zeigt. Nehmen wir weiter an, m_meinsuchwert = 2. Dann schauen wir mal, was passiert:
MyType::iterator kc; kc = p->second->begin(); // setze auf anfang while ( kc != p->second->end() ) // gehe alle key's in der 2ten map durch { if( kc->second == m_meinsuchwert ) // wenn wert gefunden { CString copy = kc->first; kc++; // zeige auf nächsten p1->erase(copy); // lösche // lösche von mapzeiger } ++kc; }
Erster Durchlauf der while-Schleife: if-Bedingung nicht erfüllt, da kc->second == 1 != 2 ist. if wird übersprungen, kc wird um eins erhöht und zeigt jetzt auf den Eintrag key2. Klar?
Zweiter Durchlauf: if-Bedingung ist ERFÜLLT, Code springt in die if-Schleife: Hier passiert jetzt folgendes: Du speicherst den Key des Iterators zwischen in copy. Dann erhöhst du den Iterator kc. Diesr zeigt jetzt in diesem Moment auf key3, logisch. Nun löschst du den gefundenen Eintrag mit seinem Key (meine Methode löscht ihn per Iterator, was schneller ist).
Ok, if-Block wird verlassen, und was passiert jetzt? Genau: kc wird NOCHMAL erhöht und zeigt jetzt auf key4! Mit diesem wird jetzt der dritte Durchlauf gestartet.key3 wurde aber nie angeschaut! Dummerweise hat key3 einen Wert gespeichert, der deinem Suchkriterium entspricht -> Fehler!
Verständlich?
-
Übrigens, der Fehler in meinem Code ist natürlich ein blöder Flüchtigkeitsfehler. So wäre er richtig:
if( kc->second == m_meinsuchwert ) // wenn wert gefunden p1->erase(kc++); // lösche // lösche von mapzeiger else ++kc;
-
argggggggggghhhhhhhhhhhhhhhhh
mein fehler soooooooooooooory
und danke für deine mühe
ihc habe das
else{ // <----------- dieses else habe ich vergessen. in meinem code hatte ich es schon nur hier im forum nicht :( ++kc; }
sooooorrrryyyyyyyyyyyyyyyyy
danke für die mühe. ich habs nicht gecheckt, das die else bed. hier nicht enthalten war
in meinem projekt aber schon
i know, kann passieren.
-
ok deine variante geht auch
aber auch nur weil ich dasMyType *p1 = p->second; // hier ZEIGER auf map
noch hingeschrieben habe. mit dem p oder mit dem mapnamen geht nicht
( wie du ja im urpost gehabt hast
)
-
Ok, dann war's ein Missverständnis, wenn du die else-Bedingung hattest. Klar, das merkt man dann auch nicht und redet aneinander vorbei
Ich würde dir aber empfehlen, den Iterator zum Löschen zu verwenden (wie in meinem Beispiel), nicht den Key, wie du es tust. Den Key muss die Map ja erst wieder suchen, und dadurch machst du der Map quasi doppelte Arbeit, wenn du den korrekten Iterator eh schon hast
-
maplover schrieb:
(Tipp: füge zwei mal den Suchwert ein für Keys die aufeinander folgen
)
Ich würd an deiner stelle stl map nochmals durcharbeiten
maplover schrieb:
ne map kann keinen doppelten key eintrag haben, per definition schon. deshalb kann ich gar keinen key 2 mal einfügen
Lern lesen. ("Keys die aufeinander folgen")
maplover schrieb:
ist keine multimap. deshalb kann ich einfach nach dem key suchen und ihn als wert löschen
Auch wenn's nicht allzu viel Sinn macht so zu verfahren wenn du den Iterator schon hast, ja, stimmt. Allerdings kannst du das bei einer multimap (m.m.) auch, und wo versteckt sich der Zusammenhang zu meinem Post?
maplover schrieb:
ich habe gerade die map schon getestet. key einfügen, löschen, mehrere löschen ( letzte/erste ) alle löschen usw.
und die map passte immer,Naja, wenn DU keinen Fehler entdecken konntest dann muss es ja korrekt sein, hm?
maplover schrieb:
weiss jetzt wirklich nicht warum nur in den hälften der fälle lieber @finix
Mein erneuter Rat: Lern lesen. Ich habe nirgends von der Hälfte der Fälle gesprochen.
Und ganz nebenbei macht es sich glaub ich nicht allzu toll sich so blasiert und herablassend zu geben wenn man Hilfe sucht, unabhängig davon ob man Recht oder, wie du, lieber @maplover, Unrecht hat.