2012-07-27 15 views
6

Angenommen, ich möchte Elemente nach bestimmten Kriterien entfernen. Lassen Sie uns sagen:Wie entferne ich Werte aus einer QMap?

QMap<int, int> map; 

und ich möchte alle Elemente entfernen, wo Wert eine ungerade Zahl ist. Wenn ich einen Iterator verwenden:

for (auto it = map.begin(); it != map.end(); ++it) 
    if (it.value() % 2 == 1) 
     map.remove(it.key()); 

Dieser Code ist wahrscheinlich falsch, da der Aufruf von

map.remove(it.key()) 

der Iterator ungültig. Wie kann ich dies tun, ohne den Iterator nach jeder Entfernung zurückzusetzen?

+2

Das wird mir helfen zu denken: http://StackOverflow.com/Questions/263945/what-Happens-If-Sie-Call-erase-on-A-Map-Element-while-iterating-from-begin-to – Andrew

Antwort

16

Verwenden QMap::erase statt, die einen Iterator auf das Element kehrt nach dem Sie gerade gelöscht:

for (auto it = map.begin(); it != map.end();) 
    if (it.value() % 2 == 1) 
     it = map.erase(it); 
    else 
     ++it; 

Ein anderer Weg ist die postfix Schritt Bediener auf dem Iterator zu verwenden:

for (auto it = map.begin(); it != map.end();) 
    if (it.value() % 2 == 1) 
     map.erase(it++); 
    else 
     ++it; 

Ein anderer Weg (und wahrscheinlich weniger effizient) ist die Verwendung des STL remove_copy_if Algorithmus, gefolgt von swap:

bool valueIsOdd(int value) {return value % 2 == 1;} 

QMap<int,int> b; 
std::remove_copy_if(a.begin(), a.end(), 
        std::inserter(b, b.end()), 
        &valueIsOdd); 
a.swap(b); 

Ich kann das letzte Beispiel im Moment nicht testen.

+2

Sie sollten nur "es" erhöhen, wenn Sie ein Element nicht entfernt haben; Andernfalls werden Sie das nächste Element verpassen. –

+0

Hoppla! Fest. Vielen Dank. –

+0

Oder verwenden Sie einfach [QMutableMapIterator] (http://doc.qt.io/qt-5/qmutablemapiterator.html#details). –

4

Sie wäre besser dran, mit dem mehr STL-like erase Funktion:

  • Es dauert einen Iterator als Argument, und so keine Zeit verschwenden durch seinen Schlüssel für das Element suchen, wenn Sie bereits wissen, wo ist es;
  • Es gibt einen Iterator für das nächste Element zurück, so dass Sie anschließend weiter iterieren können.

Mit diesem können Sie Ihre Schleife implementieren korrekt als:

for (auto it = map.begin(); it != map.end(); /* don't increment here */) { 
    if (it.value() % 2 == 1) { 
     it = map.erase(it); 
    } else { 
     ++it; 
    } 
} 

ich glaube, Sie das gleiche Ergebnis von map.remove((it++).key()) bekommen konnte, aber das würde sowohl langsamer und unübersichtlicher als erase sein.

Verwandte Themen