std::erase_if în C++

std::vector C++20

Șterge dintr-un container toate elementele egale cu o valoare (std::erase) sau care îndeplinesc o condiție (std::erase_if).

Sintaxă
template<class T, class Pred>
size_type erase_if(std::vector<T>& v, Pred conditie);

template<class T, class U>
size_type erase(std::vector<T>& v, const U& valoare);

Ce face std::erase_if

std::erase(v, x) șterge toate elementele egale cu x, iar std::erase_if(v, conditie) pe cele pentru care funcția conditie returnează true. Ambele returnează câte elemente au fost șterse. Elementele rămase își păstrează ordinea.

Înainte de C++20, același lucru se scria cu idiomul „erase-remove”: v.erase(std::remove_if(v.begin(), v.end(), conditie), v.end());. Varianta nouă este mai scurtă și nu poți uita a doua jumătate.

Funcțiile există pentru std::vector, std::string, std::deque, std::list și, ca std::erase_if, pentru std::map, std::set și containerele neordonate.

Parametri

Parametru Descriere
v Containerul din care se șterge.
valoare Pentru std::erase: elementele egale cu ea sunt șterse.
conditie Pentru std::erase_if: o funcție (de obicei o lambda) care primește un element și returnează bool.

Ce returnează

Numărul de elemente șterse.

Exemple

Exemplul 1: Ștergerea după valoare și după condiție

#include <print>
#include <vector>

int main() {
    std::vector<int> note{5, 9, 4, 10, 4, 7, 3};
    auto sterse = std::erase(note, 4);
    std::println("Am șters {} note de 4: {}", sterse, note);

    sterse = std::erase_if(note, [](int n) { return n < 5; });
    std::println("Note sub 5 șterse: {}; rămân: {}", sterse, note);
}

Rezultat

Am șters 2 note de 4: [5, 9, 10, 7, 3]
Note sub 5 șterse: 1; rămân: [5, 9, 10, 7]

Exemplul 2: Pe texte și pe un std::map

La std::map, condiția primește perechea cheie-valoare.

#include <map>
#include <print>
#include <string>
#include <vector>

int main() {
    std::vector<std::string> produse{"lapte", "", "pâine", "", "ouă"};
    std::erase(produse, "");
    std::println("{}", produse);

    std::map<std::string, int> stoc{{"mere", 0}, {"pere", 12}, {"prune", 0}};
    std::erase_if(stoc, [](const auto& pereche) { return pereche.second == 0; });
    std::println("{}", stoc);
}

Rezultat

["lapte", "pâine", "ouă"]
{"pere": 12}

Exemplul 3: Varianta veche: erase-remove

std::remove_if doar mută elementele păstrate la început și returnează unde se termină; erase taie restul.

#include <algorithm>
#include <print>
#include <vector>

int main() {
    std::vector<int> v{1, 2, 3, 4, 5, 6};
    v.erase(std::remove_if(v.begin(), v.end(), [](int x) { return x % 2 == 0; }), v.end());
    std::println("{}", v);
}

Rezultat

[1, 3, 5]

Greșeli frecvente

  • Apelezi doar std::remove(v.begin(), v.end(), x) și crezi că vectorul s-a micșorat. std::remove nu schimbă dimensiunea; folosește std::erase(v, x).
  • Ștergi elemente cu erase într-o buclă for (auto x : v), ceea ce invalidează iteratorii buclei. std::erase_if face asta corect, dintr-o singură trecere.

Comenzi înrudite

  • std::vector::erase: Șterge un element sau un interval de elemente din vector și returnează iteratorul elementului de după.
  • std::remove_if: Elimină logic elementele care îndeplinesc o condiție; folosit cu erase sau înlocuit de std::erase_if (C++20).
  • std::list::remove: remove() șterge din listă toate elementele egale cu o valoare; unique() șterge duplicatele consecutive.
  • std::map::erase: Șterge din map o cheie (cu valoarea ei), elementul indicat de un iterator sau un interval.