Ich habe versucht, eine Reihe von Elementen aus der Karte zu löschen, basierend auf einer bestimmten Bedingung. Wie mache ich das mit STL-Algorithmen?
Anfangs dachte ich an die Verwendung, remove_if
aber es ist nicht möglich, da remove_if für assoziative Container nicht funktioniert.
Gibt es einen äquivalenten "remove_if" -Algorithmus, der für die Karte funktioniert?
Als einfache Option dachte ich daran, die Karte zu durchlaufen und zu löschen. Aber ist das Durchlaufen der Karte und das Löschen eine sichere Option? (Da Iteratoren nach dem Löschen ungültig werden)
Ich habe folgendes Beispiel verwendet:
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;
}
for(auto iter=aMap.begin(); iter!=aMap.end(); ){ ....}
Unordnung reduzieren. Ruhe ist wie andere sagten. Diese Frage ersparte mir gerade einige Haarspalterei ;-)Antworten:
Fast.
Was Sie ursprünglich hatten, würde den Iterator zweimal erhöhen, wenn Sie ein Element daraus löschen würden. Sie könnten möglicherweise Elemente überspringen, die gelöscht werden mussten.
Dies ist ein gängiger Algorithmus, den ich an vielen Stellen verwendet und dokumentiert habe.
[BEARBEITEN] Sie haben Recht, dass Iteratoren nach einem Löschvorgang ungültig werden, aber nur Iteratoren, die auf das gelöschte Element verweisen, andere Iteratoren sind noch gültig. Daher
iter++
imerase()
Anruf verwenden.quelle
map
, den nächsten Iterator von zurückgebenerase(iter)
. Es ist viel sauberer zu tuniter = erase( iter )
.erase_if für std :: map (und andere Container)
Ich benutze die folgende Vorlage für genau diese Sache.
Dies gibt nichts zurück, entfernt jedoch die Elemente aus der std :: map.
Anwendungsbeispiel:
Zweites Beispiel (ermöglicht die Übergabe eines Testwerts):
quelle
std
. Ich verstehe, warum es kein Mitglied von iststd::map
, aber ich denke, so etwas sollte in der Standardbibliothek sein.std::map
und andere hinzugefügt .Jetzt
std::experimental::erase_if
ist in der Kopfzeile verfügbar<experimental/map>
.Siehe: http://en.cppreference.com/w/cpp/experimental/map/erase_if
quelle
Ich habe diese Dokumentation von der ausgezeichneten SGI STL-Referenz erhalten :
Der Iterator, der auf das zu löschende Element zeigt, wird natürlich ungültig. Mach so etwas:
quelle
erase
aufgerufen wird. Sie sind also in der Tat gleichwertig. Trotzdem würde ich Ihre Version dem Original vorziehen.Der ursprüngliche Code hat nur ein Problem:
Hier wird das
iter
einmal in der for-Schleife und ein anderes Mal beim Löschen inkrementiert, was wahrscheinlich in einer Endlosschleife enden wird.quelle
Hier ist eine elegante Lösung.
quelle
Aus den Grundtönen von:
http://www.sgi.com/tech/stl/PairAssociativeContainer.html
Ein paarassoziativer Container kann keine veränderlichen Iteratoren bereitstellen (wie in den Anforderungen für triviale Iteratoren definiert), da der Werttyp eines veränderlichen Iterators zuweisbar sein muss und das Paar nicht zuweisbar ist. Ein paarassoziativer Container kann jedoch Iteratoren bereitstellen, die nicht vollständig konstant sind: Iteratoren, sodass der Ausdruck (* i) .second = d gültig ist.
quelle
Zuerst
Zweitens ist der folgende Code gut
Beim Aufruf einer Funktion werden die Parameter vor dem Aufruf dieser Funktion ausgewertet.
Wenn also iter ++ vor dem zu löschenden Aufruf ausgewertet wird, gibt der ++ - Operator des Iterators das aktuelle Element zurück und zeigt nach dem Aufruf auf das nächste Element.
quelle
IMHO gibt es kein
remove_if()
Äquivalent.Sie können eine Karte nicht neu anordnen.
Sie
remove_if()
können also Ihre Interessenpaare nicht an das Ende setzen, an dem Sie anrufen könnenerase()
.quelle
Basierend auf der Antwort von Iron Saviour Für diejenigen, die eine größere Reichweite im Sinne von Standard-Funktions-Iteratoren bieten möchten.
Neugierig, ob es eine Möglichkeit gibt, die
ContainerT
Gegenstände zu verlieren und diese vom Iterator zu erhalten.quelle
Steve Follys Antwort ich umso effizienter.
Hier ist eine weitere einfache, aber weniger effiziente Lösung :
Die Lösung
remove_copy_if
kopiert die gewünschten Werte in einen neuen Container und tauscht dann den Inhalt des ursprünglichen Containers gegen den des neuen aus:quelle
Wenn Sie alle Elemente mit einem Schlüssel größer als 2 löschen möchten, ist der beste Weg
Funktioniert jedoch nur für Bereiche, nicht für Prädikate.
quelle
Ich benutze so
quelle