librerias - push_back c++
Borre/elimine contenidos del mapa(o cualquier otro contenedor STL) mientras lo itera (9)
1.For std::vector<>
:
std::vector <int> vec;
vec.erase(std::remove(vec.begin(),vec.end(), elem_to_remove), vec.end());
2. Para std::map<>
siempre use std::map::erase()
std::map<int,std::string> myMap;
myMap.emplace(std::make_pair(1, "Hello"));
myMap.emplace(std::make_pair(2, "Hi"));
myMap.emplace(std::make_pair(3, "How"));
myMap.erase( 1);//Erase with key
myMap.erase(myMap.begin(), ++myMap.begin() );//Erase with range
for( auto &ele: myMap)
{
if(ele.first ==1)
{
myMap.erase(ele.first);//erase by key
break; //You can''t use ele again properly
//wthin this iteration, so break.
}
}
- Para
std::list
usestd::list::erase()
Al parecer, no puede simplemente borrar / eliminar un elemento en un contenedor mientras se repite cuando el iterador se vuelve inválido. ¿Cuáles son las formas (seguras) de eliminar los elementos que cumplen una determinada condición? por favor solo stl, no boost o tr1.
EDITAR ¿Existe una forma más elegante si quiero borrar una serie de elementos que cumplen con ciertos criterios, tal vez con el uso de un algoritmo funtor y for_each o erase?
Ejemplo con std :: vector
#include <vector>
using namespace std;
int main()
{
typedef vector <int> int_vector;
int_vector v(10);
// Fill as: 0,1,2,0,1,2 etc
for (size_t i = 0; i < v.size(); ++i){
v[i] = i % 3;
}
// Remove every element where value == 1
for (int_vector::iterator it = v.begin(); it != v.end(); /* BLANK */){
if (*it == 1){
it = v.erase(it);
} else {
++it;
}
}
}
La solución de Viktor tiene la ventaja de poder hacer algo con el elemento antes de quitarlo. (No pude hacer esto con remove_if
o remove_copy_if
.) Pero prefiero usar std::find_if
para no tener que incrementar el iterador por mi cuenta:
typedef vector<int> int_vector;
int_vector v;
int_vector::iterator itr = v.begin();
for(;;)
{
itr = std::find_if(itr, v.end(), Predicate(4));
if (itr == v.end())
{
break;
}
// do stuff with *itr here
itr = v.erase(itr); // grab a new, valid iterator
}
Donde Predicado podría ser bind1st( equal_to<int>(), 4 )
o algo como esto:
struct Predicate : public unary_function<int, bool>
{
int mExpected;
Predicate(int desired) : mExpected(desired) {}
bool operator() (int input)
{
return ( input == mExpected );
}
};
Prefiero la versión con while
:
typedef std::list<some_class_t> list_t;
void f( void ) {
// Remove items from list
list_t::iterator it = sample_list.begin();
while ( it != sample_list.end() ) {
if ( it->condition == true ) {
it = sample_list.erase( it );
} else ++it;
}
}
Con while
no hay peligro de incrementarlo dos veces, ya que podría estar dentro for
bucle.
Puede hacerlo siempre que no invalide su iterador después de haberlo borrado:
MyContainer::iterator it = myContainer.begin();
while(it != myContainer.end())
{
if (*it == matchingValue)
{
myContainer.erase(it++);
}
else
{
++it;
}
}
Utilice el hecho de que el operador posterior al decremento devuelve una copia del iterador antes de decrementar. Dado que el iterador decrementado sigue siendo válido después de borrar el elemento actual, el bucle for continúa funcionando según lo previsto.
#include <list>
std::list<int> myList;
for(int i = 0; i < 10; ++i )
{
myList.push_back(i);
}
int cnt = 0;
for(std::list<int>::iterator iter = myList.begin(); iter != myList.end(); ++iter)
{
if( cnt == 5 )
{
myList.erase(iter--);
}
++cnt;
}
Edición: no funciona si intenta borrar el primer elemento de la lista ...
markh44 es la respuesta más STL-ish. Sin embargo, tenga en cuenta que, en general, los iteradores se invalidan modificando el contenedor, pero set y map son excepciones. Allí, puede eliminar elementos y seguir utilizando los iteradores, excepto si elimina el mismo elemento al que hace referencia su iterador.
bool IsOdd( int i )
{
return (i&1)!=0;
}
int a[] = {1,2,3,4,5};
vector<int> v( a, a + 5 );
v.erase( remove_if( v.begin(), v.end(), bind1st( equal_to<int>(), 4 ) ), v.end() );
// v contains {1,2,3,5}
v.erase( remove_if( v.begin(), v.end(), IsOdd ), v.end() );
// v contains {2}
template <class Container, class Predicate>
void eraseIf( Container& container, Predicate predicate ) {
container.erase( remove_if( container.begin(), container.end(), predicate ), container.end() );
}
// pre-c++11 version
template<class K, class V, class Predicate>
void eraseIf( std::map<K,V>& container, Predicate predicate) {
typename std::map<K,V>::iterator iter = container.begin();
while(iter!=container.end()) {
iterator current = iter++;
if(predicate(*current))
container.erase(current);
}
}
// c++11 version
template<class K, class V, class Predicate>
void eraseIf( std::map<K,V>& container, Predicate predicate) {
auto iter = container.begin();
while(iter!=container.end()) {
if(predicate(*iter))
iter = container.erase(iter);
else
++iter;
}
}