2009-05-17 9 views
344

Ho uno std :: vector < int> e desidero eliminare l'elemento n'th. Come lo faccio?Come si cancella un elemento da std :: vector <> per indice?

std::vector<int> vec; 

vec.push_back(6); 
vec.push_back(-17); 
vec.push_back(12); 

vec.erase(???); 
+4

Considerare l'utilizzo di un codice std :: che fornisce l'inserimento e l'eliminazione a entrambe le estremità. – Dario

+11

No, non considerare l'utilizzo di deque solo perché potresti voler eliminare un elemento, questo è un consiglio davvero scarso. C'è un sacco di motivi per cui potresti voler usare deque o vector. È vero che eliminare un elemento da un vettore può essere costoso, specialmente se il vettore è grande, ma non c'è motivo di pensare che un deque sarebbe meglio di un vettore dell'esempio di codice che hai appena postato. – Owl

+2

Ad esempio, se si dispone di un'applicazione grafica in cui viene visualizzato un "elenco" di cose in cui si inseriscono/rimuovono le cose in modo interattivo, considerare di scorrere l'elenco da 50 a 100 volte al secondo per visualizzarle e aggiungere/rimuovere elementi a poche volte al minuto. Quindi implementare la "lista" come vettore è probabilmente una scelta migliore in termini di efficienza totale. –

risposta

460

Per cancellare un singolo elemento, si potrebbe fare:

std::vector<int> vec; 

vec.push_back(6); 
vec.push_back(-17); 
vec.push_back(12); 

// Deletes the second element (vec[1]) 
vec.erase(vec.begin() + 1); 

Oppure, per eliminare più di un elemento alla volta:

// Deletes the second through third elements (vec[1], vec[2]) 
vec.erase(vec.begin() + 1, vec.begin() + 3); 
+15

Nota anche l'operatore binario '' è __not__ necessariamente definito per gli iteratori su altri tipi di contenitori, come 'lista :: iterator' (non puoi fare' list.begin() + 2' su 'std :: list', hai per usare ['std :: advance'] (http://www.cplusplus.com/reference/iterator/advance/) per quello) – bobobobo

+0

affermi che il" +1 "è il primo elemento di myVector [0] o la posizione attuale myVector [1] –

+0

it + 1 è l'elemento con ID 1, ad es. contenitore [1]. il primo elemento è +0. Vedere il commento sotto ... – Nick

159

Il metodo di cancellazione su std :: vector è sovraccarico, quindi è probabilmente più chiaro chiamare

vec.erase(vec.begin() + index); 

quando si desidera cancellare un singolo elemento.

+0

Questo non va bene se si ha solo un elemento ... non si controlla l'indice ... – alap

+2

Ma quel problema appare indipendentemente dal numero di elementi che si hanno. –

+11

se c'è solo un elemento, l'indice è 0 e quindi si ottiene 'vec.begin()' che è valido. –

39
template <typename T> 
void remove(std::vector<T>& vec, size_t pos) 
{ 
    std::vector<T>::iterator it = vec.begin(); 
    std::advance(it, pos); 
    vec.erase(it); 
} 
+2

Max, ciò che rende questa funzione migliore di: 'modello void remove (std :: vector & vec, size_t pos) {vec.erase (vec.begin + pos); } 'Non sto dicendo che sia meglio, semplicemente chiedendo l'interesse personale e restituendo il risultato migliore che questa domanda potrebbe ottenere. –

+9

@JoeyvG: Poiché un 'vector :: iterator' è un iteratore ad accesso casuale, la tua versione è soddisfacente e forse un po 'più chiara. Ma la versione che Max ha pubblicato dovrebbe funzionare bene se si cambia il contenitore in un altro che non supporta iteratori ad accesso casuale –

+1

Questa è la risposta migliore, poiché si applica anche ad altri formati di contenitore. Puoi anche usare std :: next(). – Bim

8

Procedimento erase verrà utilizzato in due modi:

  1. Cancellazione singolo elemento:

    vector.erase(vector.begin() + 3); // Deleting the third element 
    
  2. gamma Cancellazione di elementi:

    vector.erase(vector.begin() + 3, vector.begin() + 5); // Deleting from third element to fifth element 
    
1

Se si lavora con i grandi vettori (dimensioni> 100.000) e da eliminare un sacco di elementi, mi sento di raccomandare a fare qualcosa di simile:

int main(int argc, char** argv) { 

    vector <int> vec; 
    vector <int> vec2; 

    for (int i = 0; i < 20000000; i++){ 
     vec.push_back(i);} 

    for (int i = 0; i < vec.size(); i++) 
    { 
     if(vec.at(i) %3 != 0) 
      vec2.push_back(i); 
    } 

    vec = vec2; 
    cout << vec.size() << endl; 
} 

Il codice prende ogni numero in vec che non può essere diviso per 3 e lo copia in vec2. Successivamente copia vec2 in vec. È piuttosto veloce Per elaborare 20.000.000 di elementi questo algoritmo impiega solo 0,8 sec!

Ho fatto la stessa cosa con la cancellazione metodo, e ci vuole un sacco di tempo:

Erase-Version (10k elements) : 0.04 sec 
Erase-Version (100k elements) : 0.6 sec 
Erase-Version (1000k elements): 56 sec 
Erase-Version (10000k elements): ...still calculating (>30 min) 
+5

come risponde la domanda? –

+3

Interessante, ma non pertinente alla domanda! – Roddy

+0

Non sarà un algoritmo sul posto più veloce? – user202729

3

In realtà, la funzione erase lavora per due profili:

  • Rimozione di un elemento singolo

    iterator erase (iterator position); 
    
  • Rimozione di un intervallo di elementi

    iterator erase (iterator first, iterator last); 
    

Dal std :: vec.begin() segna l'inizio di contenitore e, se vogliamo eliminare l'elemento i-esimo nel nostro vettore, possiamo usare:

vec.erase(vec.begin() + index); 

Se guarda da vicino, vec.begin() è solo un puntatore alla posizione di partenza del nostro vettore e aggiungendo il valore di i ad esso incrementa il puntatore I POSIZIONE, così invece si può accedere al puntatore all'elemento i-esimo da:

&vec[i] 

Così possiamo scrivere:

vec.erase(&vec[i]); // To delete the ith element 
2

per eliminare un elemento di utilizzare il seguente modo:

 1 // declaring and assigning array1 
    2 std:vector<int> array1 {0,2,3,4}; 
    3 
    4 // erasing the value in the array 
    5 array1.erase(array1.begin()+n); 

per più ampia panoramica si possono visitare: - http://www.cplusplus.com/reference/vector/vector/erase/

0

Le risposte precedenti presumono che tu sempre abbia un indice firmato. Purtroppo, std::vector utilizza size_type per l'indicizzazione e difference_type per l'aritmetica di iteratore, quindi non funzionano insieme se si dispone di "-Wversion" e di amici abilitati. Questo è un altro modo per rispondere alla domanda, pur essendo in grado di gestire entrambi firmati e non firmati:

Per rimuovere:

template<class T, class I, class = typename std::enable_if<std::is_integral<I>::value>::type> 
void remove(std::vector<T> &v, I index) 
{ 
    const auto &iter = v.cbegin() + gsl::narrow_cast<typename std::vector<T>::difference_type>(index); 
    v.erase(iter); 
} 

Per fare:

template<class T, class I, class = typename std::enable_if<std::is_integral<I>::value>::type> 
T take(std::vector<T> &v, I index) 
{ 
    const auto &iter = v.cbegin() + gsl::narrow_cast<typename std::vector<T>::difference_type>(index); 

    auto val = *iter; 
    v.erase(iter); 

    return val; 
} 
2

Se si dispone di un vettore non ordinata si può trarre vantaggio dal fatto che non è ordinato e utilizzare qualcosa che ho visto da Dan Higgins a CPPCON

template< typename TContainer > 
static bool EraseFromUnorderedByIndex(TContainer& inContainer, size_t inIndex) 
{ 
    if (inIndex < inContainer.size()) 
    { 
     if (inIndex != inContainer.size() - 1) 
      inContainer[inIndex] = inContainer.back(); 
     inContainer.pop_back(); 
     return true; 
    } 
    return false; 
} 

Poiché l'ordine dell'elenco non ha importanza, basta prendere l'ultimo elemento nell'elenco e copiarlo sopra l'elemento superiore che si desidera rimuovere, quindi compila ed elimina l'ultimo elemento.

Problemi correlati