2016-12-22 4 views
7

Der Versuch, eine Methode zu schreiben, die die ersten (niedrigstgetasteten) N-Elemente aus einer std :: map löscht. Versucht das:Löschen Sie die ersten N Elemente von einer std :: map?

Es funktioniert, wenn die Anzahl der Elemente ist mehr als die Anzahl der Elemente entfernt werden soll. Also, wenn ich fünf Elemente hatte, um 2 zu löschen, bleiben die letzten 3 Elemente übrig. Wenn ich jedoch ein Element und die Anforderung habe, 2 zu löschen, habe ich noch ein Element übrig.

Gibt es eine gute Möglichkeit, dies zu bedecken? Ich könnte eine IF-Anweisung herumschieben, um nach numElementsToRemove größer als map.size() zu suchen, aber es muss eine bessere Lösung geben?

+4

Warum sollte es eine bessere Lösung als die einfachste Lösung geben? –

Antwort

4

std::advance(i, n) hat eine Vorbedingung, dass i mindestens n mal inkrementiert werden kann. In Ihrem Code überprüfen Sie diese Vorbedingung nicht. Wenn Sie sie also mit numElementsToRemove > originalSize aufrufen, verstoßen Sie gegen diese Voraussetzung und erfahren Undefined Behavior. Um dies zu beheben, müssen Sie den Scheck tun, bevor std::advance anrufen, vielleicht mit std::min:

auto realNumToRemove = std::min(numElementsToRemove, originalSize); 
std::advance(eraseIter, realNumToRemove); 
4

Eine if Aussage liefert eine einfache, gut lesbare Lösung:

if (originalSize <= numElementsToRemove) { 
    auto eraseIter = _map.begin(); 
    std::advance(eraseIter, numElementsToRemove); 

    _map.erase(_map.begin(), eraseIter); 
} else { 
    _map.clear(); // or whatever's appropriate 
} 
1

Die einfachste Art und Weise kann ich sehen, dies zu tun wäre std::next und eine if-Anweisung zu verwenden.

void EraseNMapElements(const int numElementsToRemove) 
{ 
    if (_map.size() < numElementsToRemove) 
     _map.erase(_map.begin(), std::next(_map.begin(), numElementsToRemove)); 
    else 
     _map.clear(); 
} 

beachten Sie aber, dass _map.size() < numElementsToRemove ein Zeichen/unsigned Mismatch hat. Vorzugsweise sollte numElementsToRemove eine std::size_t oder sein.

2

Eine Sache, die noch nicht erwähnt wurde und gut zu wissen ist, dass seit C++ 11 std :: map :: erase (const_iterator) tatsächlich einen Iterator für das folgende Element zurückgibt. So könnte der Code auch geschrieben werden als:

auto i = _map.begin(); 
while (i != _map.end() && numElementsToRemove > 0) 
{ 
    i = _map.erase(i); 
    --numElementsToRemove; 
} 

Dies wird durchlaufen die Elemente zu löschen einmal statt zweimal.

+2

Wahr. Gleichzeitig ist es durchaus möglich, dass das Löschelement mit mehreren Elementen optimiert wird, um die Anzahl der benötigten Ausgleichsoperationen im Vergleich zu einmaligem Löschen drastisch zu reduzieren. Wie immer: Wenn Sie Leistung betrachten, messen Sie. – Angew

Verwandte Themen