
naveen
Quiero borrar un elemento de un vector usando el método de borrado. Pero el problema aquí es que no se garantiza que el elemento ocurra solo una vez en el vector. Puede estar presente varias veces y necesito borrarlas todas. Mi código es algo como esto:
void erase(std::vector<int>& myNumbers_in, int number_in)
{
std::vector<int>::iterator iter = myNumbers_in.begin();
std::vector<int>::iterator endIter = myNumbers_in.end();
for(; iter != endIter; ++iter)
{
if(*iter == number_in)
{
myNumbers_in.erase(iter);
}
}
}
int main(int argc, char* argv[])
{
std::vector<int> myNmbers;
for(int i = 0; i < 2; ++i)
{
myNmbers.push_back(i);
myNmbers.push_back(i);
}
erase(myNmbers, 1);
return 0;
}
Este código obviamente falla porque estoy cambiando el final del vector mientras lo itero. ¿Cuál es la mejor manera de lograr esto? Es decir, ¿hay alguna forma de hacer esto sin iterar el vector varias veces o crear una copia más del vector?

Motti
Utilizar el quitar/borrar idioma:
std::vector<int>& vec = myNumbers; // use shorter name
vec.erase(std::remove(vec.begin(), vec.end(), number_in), vec.end());
lo que pasa es que remove
compacta los elementos que difieren del valor a eliminar (number_in
) al principio de la vector
y devuelve el iterador al primer elemento después de ese rango. Luego erase
elimina estos elementos (cuyo valor no se especifica).

dalle
Llamar a erase invalidará los iteradores, podría usar:
void erase(std::vector<int>& myNumbers_in, int number_in)
{
std::vector<int>::iterator iter = myNumbers_in.begin();
while (iter != myNumbers_in.end())
{
if (*iter == number_in)
{
iter = myNumbers_in.erase(iter);
}
else
{
++iter;
}
}
}
O podrías usar estándar::remove_if junto con un funtor y std::vector::erase:
struct Eraser
{
Eraser(int number_in) : number_in(number_in) {}
int number_in;
bool operator()(int i) const
{
return i == number_in;
}
};
std::vector<int> myNumbers;
myNumbers.erase(std::remove_if(myNumbers.begin(), myNumbers.end(), Eraser(number_in)), myNumbers.end());
En lugar de escribir su propio funtor en este caso, podría usar estándar::eliminar:
std::vector<int> myNumbers;
myNumbers.erase(std::remove(myNumbers.begin(), myNumbers.end(), number_in), myNumbers.end());
En C++ 11, podría usar una lambda en lugar de un funtor:
std::vector<int> myNumbers;
myNumbers.erase(std::remove_if(myNumbers.begin(), myNumbers.end(), [number_in](int number){ return number == number_in; }), myNumbers.end());
En C++17 std::experimental::borrar y std::experimental::erase_if también están disponibles, en C ++ 20 estos (finalmente) se renombran a std::borrar y std::erase_if (nota: en Visual Studio 2019, deberá cambiar su versión de lenguaje C++ a la última versión experimental para obtener soporte):
std::vector<int> myNumbers;
std::erase_if(myNumbers, Eraser(number_in)); // or use lambda
o:
std::vector<int> myNumbers;
std::erase(myNumbers, number_in);

sergtk
-
Puede iterar usando el acceso de índice,
-
Para evitar la complejidad de O (n ^ 2), puede usar dos índices, i – índice de prueba actual, j – índice para almacenar el siguiente elemento y al final del ciclo, el nuevo tamaño del vector.
código:
void erase(std::vector<int>& v, int num)
{
size_t j = 0;
for (size_t i = 0; i < v.size(); ++i) {
if (v[i] != num) v[j++] = v[i];
}
// trim vector to new size
v.resize(j);
}
En tal caso, no tiene invalidación de iteradores, la complejidad es O (n), y el código es muy conciso y no necesita escribir algunas clases auxiliares, aunque en algunos casos el uso de clases auxiliares puede beneficiar en un código más flexible.
Este código no utiliza erase
método, pero resuelve su tarea.
Usando stl puro, puede hacer esto de la siguiente manera (esto es similar a la respuesta de Motti):
#include <algorithm>
void erase(std::vector<int>& v, int num) {
vector<int>::iterator it = remove(v.begin(), v.end(), num);
v.erase(it, v.end());
}

Laserallan
Dependiendo de por qué está haciendo esto, usando un estándar::establecer podría ser una mejor idea que std::vector.
Permite que cada elemento ocurra solo una vez. Si lo agrega varias veces, solo habrá una instancia para borrar de todos modos. Esto hará que la operación de borrado sea trivial. La operación de borrado también tendrá una menor complejidad de tiempo que en el vector, sin embargo, agregar elementos es más lento en el conjunto, por lo que podría no ser una gran ventaja.
Por supuesto, esto no funcionará si está interesado en cuántas veces se ha agregado un elemento a su vector o el orden en que se agregaron los elementos.

Eduard Rostomian
Hay std::erase y std::erase_if ya que C++20 que combina el idioma quitar-borrar.
std::vector<int> nums;
...
std::erase(nums, targetNumber);
o
std::vector<int> nums;
...
std::erase_if(nums, [](int x) { return x % 2 == 0; });