Estaba tratando de borrar una variedad de elementos del mapa en función de una condición particular. ¿Cómo lo hago usando algoritmos STL?
Inicialmente pensé en usar, remove_if
pero no es posible ya que remove_if no funciona para el contenedor asociativo.
¿Existe algún algoritmo equivalente "remove_if" que funcione para el mapa?
Como una opción simple, pensé en recorrer el mapa y borrar. Pero, ¿recorrer el mapa y borrar es una opción segura? (Ya que los iteradores se vuelven inválidos después del borrado)
Usé el siguiente ejemplo:
bool predicate(const std::pair<int,std::string>& x)
{
return x.first > 2;
}
int main(void)
{
std::map<int, std::string> aMap;
aMap[2] = "two";
aMap[3] = "three";
aMap[4] = "four";
aMap[5] = "five";
aMap[6] = "six";
// does not work, an error
// std::remove_if(aMap.begin(), aMap.end(), predicate);
std::map<int, std::string>::iterator iter = aMap.begin();
std::map<int, std::string>::iterator endIter = aMap.end();
for(; iter != endIter; ++iter)
{
if(Some Condition)
{
// is it safe ?
aMap.erase(iter++);
}
}
return 0;
}
for(auto iter=aMap.begin(); iter!=aMap.end(); ){ ....}
para reducir el desorden. El descanso es como decían otros. Esta pregunta me salvó un poco de división del cabello en este momento ;-)Respuestas:
Casi.
Lo que tenía originalmente incrementaría el iterador dos veces si borrara un elemento de él; potencialmente podría omitir elementos que deben borrarse.
Este es un algoritmo común que he visto utilizado y documentado en muchos lugares.
[EDITAR] Tiene razón en que los iteradores se invalidan después de un borrado, pero solo los iteradores que hacen referencia al elemento que se borra, otros iteradores siguen siendo válidos. Por lo tanto, usar
iter++
en laerase()
llamada.fuente
map
, devuelven el siguiente iterador deerase(iter)
. Es mucho más limpio de haceriter = erase( iter )
.erase_if para std :: map (y otros contenedores)
Utilizo la siguiente plantilla para esto mismo.
Esto no devolverá nada, pero eliminará los elementos del std :: map.
Ejemplo de uso:
Segundo ejemplo (le permite pasar un valor de prueba):
fuente
std
. Entiendo por qué no es miembro destd::map
, pero creo que algo así debería estar en la biblioteca estándar.std::map
y otros.Ahora,
std::experimental::erase_if
está disponible en header<experimental/map>
.Ver: http://en.cppreference.com/w/cpp/experimental/map/erase_if
fuente
Obtuve esta documentación de la excelente referencia SGI STL :
Por lo tanto, el iterador que tiene que apunta al elemento que se va a borrar, por supuesto, se invalidará. Haz algo como esto:
fuente
erase
llamar. Entonces, de hecho, son equivalentes. Aún así, preferiría su versión sobre la original.El código original tiene un solo problema:
Aquí
iter
se incrementa una vez en el ciclo for y otra vez en el borrado, lo que probablemente terminará en un ciclo infinito.fuente
Aquí tienes una solución elegante.
fuente
De las notas inferiores de:
http://www.sgi.com/tech/stl/PairAssociativeContainer.html
un contenedor asociativo de pares no puede proporcionar iteradores mutables (como se define en los requisitos del iterador trivial), porque el tipo de valor de un iterador mutable debe ser asignable y el par no es asignable. Sin embargo, un contenedor asociativo de pares puede proporcionar iteradores que no son completamente constantes: iteradores tales que la expresión (* i) .second = d sea válida.
fuente
primero
En segundo lugar, el siguiente código es bueno
Al llamar a una función, los parámetros se evalúan antes de la llamada a esa función.
Entonces, cuando iter ++ se evalúa antes de la llamada a borrar, el operador ++ del iterador devolverá el elemento actual y apuntará al siguiente elemento después de la llamada.
fuente
En mi humilde opinión, no hay
remove_if()
equivalente.No puede reordenar un mapa.
Así
remove_if()
que no puedes poner tus pares de interés al final al que puedes llamarerase()
.fuente
Basado en la respuesta de Iron Savior Para aquellos que deseen proporcionar un rango más similar a los iteradores de toma funcionales estándar.
Es curioso si hay alguna forma de perder los
ContainerT
elementos y obtenerlos del iterador.fuente
La respuesta de Steve Folly me siento más eficiente.
Aquí hay otra solución fácil pero menos eficiente :
La solución usa
remove_copy_if
para copiar los valores que queremos en un nuevo contenedor, luego intercambia el contenido del contenedor original con los del nuevo:fuente
Si desea borrar todos los elementos con clave mayor que 2, entonces la mejor manera es
Sin embargo, solo funciona para rangos, no para ningún predicado.
fuente
Yo uso así
fuente