Come rimuovo un elemento da un vettore stl con un determinato valore?
Domanda
Stavo esaminando la documentazione dell'API per il vettore stl e ho notato che non esisteva alcun metodo nella classe vettoriale che consentisse la rimozione di un elemento con un determinato valore.Sembra un'operazione comune e sembra strano che non ci sia un modo integrato per farlo.
Soluzione
std::remove
in realtà non cancella l'elemento dal contenitore, ma restituisce il nuovo iteratore finale a cui può essere passato container_type::erase
per eseguire la VERA rimozione degli elementi extra che ora si trovano alla fine del contenitore:
std::vector<int> vec;
// .. put in some values ..
int int_to_remove = n;
vec.erase(std::remove(vec.begin(), vec.end(), int_to_remove), vec.end());
Altri suggerimenti
Se vuoi rimuovere UN elemento, quanto segue sarà un po' più efficiente.
std::vector<int> v;
auto it = std::find(v.begin(), v.end(), 5);
if(it != v.end())
v.erase(it);
oppure puoi evitare le spese generali legate allo spostamento degli articoli se l'ordine non ti interessa:
std::vector<int> v;
auto it = std::find(v.begin(), v.end(), 5);
if (it != v.end()) {
using std::swap;
// swap the one to be removed with the last element
// and remove the item at the end of the container
// to prevent moving all items after '5' by one
swap(*it, v.back());
v.pop_back();
}
Utilizza il metodo globale std::remove con l'iteratore Begin ed End, quindi utilizza std::vettore.erase per rimuovere effettivamente gli elementi.
Collegamenti alla documentazione
std::rimuovi http://www.cppreference.com/cppalgorithm/remove.html
std::vettore.erase http://www.cppreference.com/cppvettore/erase.html
std::vector<int> v;
v.push_back(1);
v.push_back(2);
//Vector should contain the elements 1, 2
//Find new end iterator
std::vector<int>::iterator newEnd = std::remove(v.begin(), v.end(), 1);
//Erase the "removed" elements.
v.erase(newEnd, v.end());
//Vector should now only contain 2
Grazie a Jim Buck per aver sottolineato il mio errore.
Le altre risposte spiegano come farlo bene, ma ho pensato di sottolineare anche che non è proprio strano che questo non sia nell'API vettoriale:è inefficiente, la ricerca lineare del valore nel vettore, seguita da una serie di operazioni di copia per rimuoverlo.
Se stai eseguendo questa operazione in modo intensivo, può valere la pena considerare std::set per questo motivo.
Se hai un vettore non ordinato, puoi semplicemente scambiarlo con l'ultimo elemento del vettore resize()
.
Con un contenitore ordinato, la soluzione migliore è std::vector::erase()
.Tieni presente che esiste un std::remove()
definito in <algorithm>
, ma questo in realtà non esegue la cancellazione.(Leggere attentamente la documentazione).
Una soluzione più breve (che non obbliga a ripetere il nome del vettore 4 volte) sarebbe quella di utilizzare Boost:
#include <boost/range/algorithm_ext/erase.hpp>
// ...
boost::remove_erase(vec, int_to_remove);
Guarda anche std::rimuovi_if poter usare un predicato...
Ecco l'esempio dal link sopra:
vector<int> V;
V.push_back(1);
V.push_back(4);
V.push_back(2);
V.push_back(8);
V.push_back(5);
V.push_back(7);
copy(V.begin(), V.end(), ostream_iterator<int>(cout, " "));
// The output is "1 4 2 8 5 7"
vector<int>::iterator new_end =
remove_if(V.begin(), V.end(),
compose1(bind2nd(equal_to<int>(), 0),
bind2nd(modulus<int>(), 2)));
V.erase(new_end, V.end()); [1]
copy(V.begin(), V.end(), ostream_iterator<int>(cout, " "));
// The output is "1 5 7".
Da c++20:
Introdotta una funzione non membro std::erase
, che accetta il vettore e il valore da rimuovere come input.
ex:
std::vector<int> v = {90,80,70,60,50};
std::erase(v,50);
Se vuoi farlo senza extra include:
vector<IComponent*> myComponents; //assume it has items in it already.
void RemoveComponent(IComponent* componentToRemove)
{
IComponent* juggler;
if (componentToRemove != NULL)
{
for (int currComponentIndex = 0; currComponentIndex < myComponents.size(); currComponentIndex++)
{
if (componentToRemove == myComponents[currComponentIndex])
{
//Since we don't care about order, swap with the last element, then delete it.
juggler = myComponents[currComponentIndex];
myComponents[currComponentIndex] = myComponents[myComponents.size() - 1];
myComponents[myComponents.size() - 1] = juggler;
//Remove it from memory and let the vector know too.
myComponents.pop_back();
delete juggler;
}
}
}
}
Esistono due modi con cui è possibile utilizzare per cancellare un elemento in particolare.Prendiamo un vettore
std :: vector < int > v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
v.push_back(40);
v.push_back(50);
1) Modo non efficiente: Anche se sembra abbastanza efficiente, ma non lo è perché la funzione di cancellazione elimina gli elementi e sposta tutti gli elementi verso sinistra di 1.quindi la sua complessità sarà O(n^2)
std :: vector < int > :: iterator itr = v.begin();
int value = 40;
while ( itr != v.end() )
{
if(*itr == value)
{
v.erase(itr);
}
else
++itr;
}
2) Modo efficiente (CONSIGLIATO) :È anche noto come CANCELLARE - RIMUOVERE gli idiomi .
- std::remove trasforma l'intervallo specificato in un intervallo con tutti gli elementi che si confrontano in modo diverso dall'elemento specificato spostati all'inizio del contenitore.
- Quindi, in realtà non rimuovere gli elementi corrispondenti.Ha semplicemente spostato la non corrispondenza all'inizio e fornisce un iteratore alla nuova fine valida.Richiede solo complessità O(n).
l'output dell'algoritmo di rimozione è:
10 20 30 50 40 50
poiché il tipo restituito di rimozione è l'iteratore fino alla nuova fine di tale intervallo.
template <class ForwardIterator, class T>
ForwardIterator remove (ForwardIterator first, ForwardIterator last, const T& val);
Ora usa la funzione di cancellazione del vettore per eliminare gli elementi dalla nuova estremità alla vecchia estremità del vettore.Richiede tempo O(1).
v.erase ( std :: remove (v.begin() , v.end() , element ) , v.end () );
quindi questo metodo funziona in O(n)