2009-05-17 5 views
344

Tengo un std :: vector < int>, y quiero eliminar el n-ésimo elemento. ¿Cómo puedo hacer eso?¿Cómo borro un elemento de std :: vector <> por índice?

std::vector<int> vec; 

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

vec.erase(???); 
+4

Considere el uso de std :: deque, que proporciona inserción y eliminación en ambos extremos. – Dario

+11

No, no considere usar deque simplemente porque es posible que desee eliminar un elemento, eso es realmente un consejo pobre. Hay una gran cantidad de razones por las que es posible que desee utilizar deque o vector. Es cierto que eliminar un elemento de un vector puede ser costoso, especialmente si el vector es grande, pero no hay motivo para pensar que un deque sea mejor que un vector del ejemplo de código que acaba de publicar. – Owl

+2

Por ejemplo, si tiene una aplicación gráfica donde muestra una "lista" de cosas donde inserta/quita cosas de manera interactiva, considere ejecutar la lista 50-100 veces por segundo para mostrarlas, y agregar/eliminar cosas algunas veces cada minuto. Entonces, implementar la "lista" como vector es probablemente una mejor opción en términos de eficiencia total. –

Respuesta

460

Para eliminar un solo elemento, que podría hacer:

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); 

O, para eliminar más de un elemento a la vez:

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

Tenga en cuenta que el 'operador +' binario es __not__ necesariamente definido para iteradores en otros tipos de contenedor, como 'list :: iterator' (no puede hacer' list.begin() + 2' en 'std :: list', tiene para usar ['std :: advance'] (http://www.cplusplus.com/reference/iterator/advance/) para eso) – bobobobo

+0

está indicando que" +1 "es el primer elemento myVector [0] o la posición real myVector [1] –

+0

it + 1 es un elemento con id 1, p. ej. contenedor [1]. primer elemento es +0. Vea el comentario a continuación ... – Nick

159

El método de borrado en std :: vector está sobrecargado, por lo que probablemente sea más claro llamar a

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

cuando solo quiere borrar un solo elemento.

+0

Esto no es bueno si solo tiene un elemento ... no verifica el índice ... – alap

+2

Pero ese problema aparece sin importar cuántos elementos tenga. –

+11

si solo hay un elemento, el índice es 0, y entonces obtienes 'vec.begin()' que es válido. –

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, lo que hace que la función sea mejor que: 'plantilla void remove (std :: vector & vec, size_t pos) {vec.erase (vec.begin + pos); } 'No estoy diciendo que ninguno sea mejor, simplemente pregunta por interés personal y para devolver el mejor resultado que pueda obtener esta pregunta. –

+9

@JoeyvG: Dado que un 'vector :: iterator' es un iterador de acceso aleatorio, su versión es buena y tal vez un poco más clara. Pero la versión que publicó Max debería funcionar bien si cambia el contenedor a otro que no admita los iteradores de acceso aleatorio –

+1

Esta es la mejor respuesta, ya que también se aplica a otros formatos de contenedor. También podría usar std :: next(). – Bim

8

El método erase se puede utilizar de dos maneras:

  1. Borrado solo elemento:

    vector.erase(vector.begin() + 3); // Deleting the third element 
    
  2. gama de borrado de elementos:

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

Si se trabaja con vectores grandes (tamaño> 100.000) y quiere eliminar una gran cantidad de elementos, que recomendaría a hacer algo como esto:

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; 
} 

El código toma cada número en el vec que no puede ser dividido por 3 y lo copia a vec2. Luego copia vec2 en vec. Es bastante rápido ¡Para procesar 20,000,000 de elementos, este algoritmo solo toma 0.8 segundos!

me hizo lo mismo con el borrado de un método, y se necesita mucho, mucho tiempo:

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

¿Cómo responde esto la pregunta? –

+3

¡Interesante, pero no relevante para la pregunta! – Roddy

+0

¿No será más rápido un algoritmo in situ? – user202729

3

En realidad, la función erase obras para dos perfiles:

  • Extracción de una solo elemento

    iterator erase (iterator position); 
    
  • Extracción de una gama de elementos

    iterator erase (iterator first, iterator last); 
    

Desde std :: vec.begin() marca el inicio del contenedor y si queremos eliminar el elemento i en nuestro vector, podemos utilizar:

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

Si mira de cerca, vec.begin() es sólo un puntero a la posición de partida de nuestro vector y añadiendo el valor de i que se incrementa el puntero de i posición, así que en vez podemos acceder al puntero al elemento i por:

&vec[i] 

Así podemos escribir:

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

Las respuestas anteriores asumen que siempre tienen un índice firmado. Tristemente, std::vector usa size_type para indexar, y difference_type para aritmética de iterador, por lo que no funcionan juntos si tiene "-Wconversion" y amigos habilitados. Esta es otra manera de responder a la pregunta, mientras que ser capaz de manejar tanto con y sin signo:

Para retirar:

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); 
} 

Tomar:

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

Si usted tiene un vector desordenada que puede aprovechar el hecho de que está desordenado y usar algo que vi de Dan Higgins en 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; 
} 

Dado que el orden de la lista no importa, simplemente tome el último elemento de la lista y cópielo en la parte superior del artículo que desea eliminar, y luego haga clic y elimine el último elemento.

Cuestiones relacionadas