Jak usunąć elementy z kontenerów STL?
Jak wymazać elementy z kontenerów STL, które mają określoną wartość lub spełniają jakiś warunek ?
Czy istnieje jeden wspólny lub jednolity sposób zrobienia tego dla różnych rodzajów kontenerów?
1 answers
Niestety, nie ma ani jednego jednolitego interfejsu ani wzorca do usuwania elementów z kontenerów STL. Pojawiają się jednak trzy zachowania:
Std:: vector Pattern
Aby usunąć elementy, które spełniają określony warunek z std::vector
, powszechną techniką jest tzw. erase-Usuń idiom.
Jeśli v
jest instancją std::vector
i chcemy wymazać elementy o wartości x
z wektora, taki kod może być używany:
// Erase elements having value "x" from vector "v"
v.erase( std::remove(v.begin(), v.end(), x), v.end() );
Jeśli kryterium wymazywania elementów jest bardziej złożone niż proste "element do wymazania = = x" , można użyć algorytmu std::remove_if()
zamiast std::remove()
:
// Erase elements matching "erasing_condition" from vector "v"
v.erase( std::remove_if(v.begin(), v.end(), erasing_condition), v.end() );
Gdzie erasing_condition
jest jednoznacznym predykatem, który może być wyrażony w kilku formach: np. może być bool
-funkcja zwracająca przyjmująca Typ elementu wektorowego jako dane wejściowe (więc jeśli zwracana wartość to true
, element zostanie usunięty z wektora; jeśli jest to false
, nie); lub może być wyrażona w linii jako lambda; może być functor; itd.
(zarówno std::remove()
, jak i std::remove_if()
są algorytmami generycznymi z nagłówka <algorithm>
.)
Tutaj jest jasne wyjaśnienie Z Wikipedii :
Biblioteka
algorithm
dostarczaremove
iremove_if
algorytmy na to. Ponieważ algorytmy te działają w zakresie elementów oznaczonych przez dwa Iteratory, nie mają wiedzy o podstawa pojemnik lub kolekcja. Tak więc żadne elementy nie są w rzeczywistości wyjęty z pojemnika. Raczej wszystkie elementy, które nie pasują do kryteria usuwania są zestawione z przodu zakresu, w ten sam względny porządek. Pozostałe elementy pozostają w poprawnym, ale nieokreślony stan. Po wykonaniu tej czynnościremove
zwraca iterator / align = "left" /Aby faktycznie wyeliminować elementy z pojemnika,
remove
jest połączone z pojemnikiemerase
funkcja członka, stąd nazwa "Wymaż-Usuń idiom".
Zasadniczo, std::remove()
i std::remove_if()
kompaktują elementy, które nie spełniają kryteriów kasowania na początku zakresu (tj. na początku vector
), a następnie erase()
eliminują pozostałe elementy z pojemnika.
Ten wzór dotyczy również innych kontenerów, takich jak std::deque
.
Std:: list Pattern
Aby usunąć elementy z std::list
, proste remove()
i remove_if()
metody są dostępne:
// Erase elements having value "x" from list "l"
l.remove( x )
// Erase elements satisfying "erasing_condition" from list "l"
l.remove_if( erasing_condition );
(gdzie erasing_condition
jest jednoznacznym predykatem, o tych samych cechach omówionych dla std::remove_if()
w powyższej sekcji.)
Ten sam wzór można zastosować do podobnych pojemników, jak std::forward_list
.
Kontenery asocjacyjne (np. std:: map, std:: set, ...) Wzór
kontenery asocjacyjne jak std::map
, std::set
, std::unordered_map
, itd. postępuj zgodnie z opisanym tutaj powszechnym wzorem:
-
Jeśli warunek kasowania jest prostym dopasowaniem klucza (np. "Wymaż element mając klucz x " ), wówczas prosty
erase()
metoda może być wywołana:// Erase element having key "k" from map "m": m.erase( k );
-
Jeśli warunek kasowania jest bardziej złożony i jest wyrażony przez pewien zwyczaj można użyć pętli "wymazać wszystkie nieparzyste elementy"), wtedy można użyć pętli
for
(z wyraźnym sprawdzaniem stanu kasowania w ciele pętli oraz wywołanie metodyerase(iterator)
):// // Erase all elements from associative container "c", satisfying "erasing_condition": // for (auto it = c.begin(); it != c.end(); /* "it" updated inside loop body */ ) { if ( erasing_condition(*it) ) { // Erase the element matching the specified condition // from the associative container. it = c.erase(it); // Note: // erase() returns an iterator to the element // that follows the last element removed, // so we can continue the "for" loop iteration from that position. } else { // Current element does _not_ satisfy erasing condition, // so we can just move on to the next element. ++it; } }
Potrzeba jednolitego podejścia
Jak można zauważyć z powyższej analizy, niestety nie ma jednolitego wspólnego podejścia do usuwania elementów z kontenerów STL.
Poniższa tabela podsumowuje wyżej wymienione wzory:
----------------+------------------------------------------ Container | Erasing Pattern ----------------+------------------------------------------ | vector | Use erase-remove idiom. deque | | ----------------+------------------------------------------ | list | Call remove()/remove_if() methods. forward_list | | ----------------+------------------------------------------ | map | Simple erase(key) method call, set | or unordered_map | loop through the container, multimap | and call erase(iterator) on matching | condition. ... | | ----------------+------------------------------------------
Pisanie specyficznego kodu na podstawie konkretnego kontenera jest podatne na błędy, trudne do utrzymania, trudne do odczytania itp.
Jednak to możliwość zapisu szablonów funkcji o nazwach zwyczajowych (np. erase()
i erase_if()
) przeciążone dla różnych typów kontenerów i osadzone wyżej wymienione implementacje wzorców w tych funkcjach.
Tak więc, klient może po prostu wywołać te erase()
i erase_if()
funkcje ogólne, a kompilator wyśle wywołanie do właściwej implementacji (w czasie kompilacji ), W oparciu o Typ kontenera.
Bardziej eleganckim podejściem, wykorzystującym technikę meta-programowania szablonów, jest przedstawione przez Stephan T. Lavavej tutaj.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:14