Löschen der ersten N Elemente aus einem std::map?

Versucht zu schreiben, eine Methode, die löscht die erste (Unterste-keyed) N von Elementen aus einer std::map. So probiert:

void EraseNMapElements(const int numElementsToRemove){

    const int originalSize = _map.size();     
    auto eraseIter = _map.begin();
    std::advance(eraseIter, numElementsToRemove);

    _map.erase(_map.begin(), eraseIter);

    assert(_map.size() == (originalSize - numElementsToRemove)) || (0 == originalSize) || (0 == _map.size()));
}

Es funktioniert, wenn die Anzahl der Elemente ist mehr als die geforderte Anzahl zu entfernen. Also, wenn ich mir fünf Elemente, die Anfrage zu löschen 2, die letzten 3-element bleiben. Allerdings, wenn ich ein element und Anfrage löschen 2, ich habe noch ein element übrig.

Ist es eine nette Möglichkeit, um dieses? Ich könnte schieben Sie eine IF-Anweisung, um die Prüfung für numElementsToRemove größer als die Karte.size() aber es muss doch eine bessere Lösung?

  • Warum wäre es eine bessere Lösung als die einfachste Lösung?
InformationsquelleAutor user997112 | 2016-12-22



4 Replies
  1. 4

    std::advance(i, n) hat eine Voraussetzung, dass i kann erhöht werden, mindestens n Zeiten. In deinem code, du bist nicht die Prüfung, die Voraussetzung, so dass, wenn Sie nennen Sie es mit numElementsToRemove > originalSize, du bist verletzt, die Voraussetzung und erlebt dadurch ein Undefiniertes Verhalten. Um das zu beheben, müssen Sie vor dem Aufruf std::advance, vielleicht mit std::min:

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

    Einer if – Anweisung stellt 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
    }
  3. 3

    Eine Sache, die noch nicht angesprochen wurde-und das ist gut zu wissen ist, dass seit C++11 std::map::erase(const_iterator) eigentlich liefert einen iterator auf das folgende element. So konnte der code auch geschrieben werden als:

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

    Diese Durchlaufen die Elemente zu löschen, einmal statt zweimal.

    • Wahr. Zur gleichen Zeit, ist es durchaus möglich, die multi-element – erase könnte optimiert werden, um drastisch reduzieren die Anzahl von balancing-Vorgänge erforderlich sind, im Vergleich zu einmal-in-a-time erasure. Wie immer: wenn man Leistung Messen.
  4. 1

    Der einfachste Weg, ich kann sehen, dies zu tun wäre, um std::next und eine if-Anweisung.

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

    Tun, beachten Sie aber, dass _map.size() < numElementsToRemove hat ein Schild/unsigned mismatch. Vorzugsweise numElementsToRemove sollte ein std::size_t oder decltype(_map)::size_type.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.