Pensez à utiliser un std :: deque qui fournit l'insertion et la suppression aux deux extrémités.
Dario
40
Non, ne pensez pas à utiliser deque simplement parce que vous voudrez peut-être supprimer un élément, c'est vraiment un mauvais conseil. Il y a toute une série de raisons pour lesquelles vous pouvez utiliser deque ou vector. Il est vrai que supprimer un élément d'un vecteur peut être coûteux - surtout si le vecteur est grand, mais il n'y a aucune raison de penser qu'un deque serait mieux qu'un vecteur de l'exemple de code que vous venez de publier.
Chouette du
6
Par exemple, si vous avez une application graphique où vous affichez une "liste" de choses où vous insérez / supprimez des choses de manière interactive, considérez que vous parcourez la liste 50-100 fois par seconde pour les afficher, et vous ajoutez / supprimez des choses quelques-unes fois par minute. La mise en œuvre de la "liste" comme vecteur est donc probablement une meilleure option en termes d'efficacité totale.
Michel Billaud
Réponses:
706
Pour supprimer un seul élément, vous pouvez faire:
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);
Ou, pour supprimer plusieurs éléments à la fois:
// Deletes the second through third elements (vec[1], vec[2])
vec.erase(vec.begin()+1, vec.begin()+3);
Notez également que le binaire operator+n'est pas nécessairement défini pour les itérateurs sur d'autres types de conteneurs, comme list<T>::iterator(vous ne pouvez pas le faire list.begin() + 2sur un std::list, vous devez l'utiliser std::advancepour cela)
bobobobo
déclarez-vous que le "+1" est le premier élément myVector [0] ou la position réelle myVector [1]
K - La toxicité dans le SO augmente.
2
Avec avance, vous devez enregistrer l'itérateur dans une variable. Si vous utilisez std :: next, vous pouvez le faire sur une seule ligne: vec.erase (next (begin (vec), 123));
dani
8
Merci à tous ceux qui ont répondu. Que penser d'une conception de classe lorsqu'une opération aussi simple que la suppression d'un élément nécessite que l'on vienne sur StackOverflow?
Pierre
5
@Pierre parce que l' indice numérique d'un élément particulier n'est pas le modèle principal d'accès, l' itérateur l' est. Toutes les fonctions qui regardent les éléments d'un conteneur utilisent les itérateurs de ce conteneur. Par exemplestd::find_if
Caleth
212
La méthode d'effacement sur std :: vector est surchargée, il est donc probablement plus clair d'appeler
vec.erase(vec.begin()+ index);
lorsque vous ne souhaitez effacer qu'un seul élément.
Mais ce problème apparaît quel que soit le nombre d'éléments dont vous disposez.
Zyx 2000
15
s'il n'y a qu'un seul élément, l'index est 0, et donc vous obtenez vec.begin()ce qui est valide.
Anne Quinn
28
Je souhaite que quelqu'un aurait mentionné que vec.erase(0)cela ne fonctionne pas, mais vec.erase(vec.begin()+0)(ou sans +0) le fait. Sinon, je ne reçois aucun appel de fonction correspondant, c'est pourquoi je suis venu ici
qrtLs
@qrtLs vec.erase(0)peut en fait se compiler s'il 0arrive d'être interprété comme la constante du pointeur nul ...
Max, ce qui rend cette fonction meilleure que: template <typename T> void remove(std::vector<T>& vec, size_t pos) { vec.erase(vec.begin + pos); }je ne dis pas que c'est mieux, simplement en demandant par intérêt personnel et en retournant le meilleur résultat que cette question pourrait obtenir.
13
@JoeyvG: Puisque a vector<T>::iteratorest un itérateur à accès aléatoire, votre version est correcte et peut-être un peu plus claire. Mais la version publiée par Max devrait fonctionner très bien si vous changez le conteneur en un autre qui ne prend pas en charge les itérateurs à accès aléatoire
Lily Ballard
2
C'est imo la meilleure réponse, car elle s'applique également à d'autres formats de conteneurs. Vous pouvez également utiliser std :: next ().
Bim
Une bien meilleure approche car elle ne repose pas sur les éléments internes du conteneur.
BartoszKP
std :: Advance n'est nécessaire que si vous pensez que ce ne sera pas un vecteur, c'est-à-dire une liste. Mais comme vous l'avez spécifié ici, l'opérateur + ne serait-il pas plus simple? Selon ce stackoverflow.com/questions/1668088/… il y a un gain de performance possible avec l'opérateur +
Neil McGill
14
La eraseméthode sera utilisée de deux manières:
Effacement d'un seul élément:
vector.erase( vector.begin()+3);// Deleting the fourth element
Effacement d'une gamme d'éléments:
vector.erase( vector.begin()+3, vector.begin()+5);// Deleting from fourth element to sixth element
Il s'agit d'une réponse en double près de 7 ans après la réponse acceptée. Veuillez ne pas faire ça.
AlastairG
10
En fait, la erasefonction fonctionne pour deux profils:
Suppression d'un seul élément
iterator erase (iterator position);
Suppression d'une gamme d'éléments
iterator erase (iterator first, iterator last);
Puisque std :: vec.begin () marque le début du conteneur et si nous voulons supprimer le ième élément de notre vecteur, nous pouvons utiliser:
vec.erase(vec.begin()+ index);
Si vous regardez attentivement, vec.begin () n'est qu'un pointeur vers la position de départ de notre vecteur et l'ajout de la valeur de i augmente le pointeur à la position i, nous pouvons donc accéder au pointeur vers le ième élément en:
-1 La dernière ligne ne se compile pas (au moins dans VS2017). Le code suppose que vector :: iterator est implicitement constructible à partir d'un pointeur brut, ce qui n'est pas requis par la norme.
CuriousGeorge
1
Cela est particulièrement vrai pour les itérateurs de débogage
Nishant Singh
9
Si vous avez un vecteur non ordonné, vous pouvez profiter du fait qu'il n'est pas ordonné et utiliser quelque chose que j'ai vu de Dan Higgins au CPPCON
Étant donné que l'ordre des listes n'a pas d'importance, prenez simplement le dernier élément de la liste et copiez-le par-dessus l'élément que vous souhaitez supprimer, puis sautez et supprimez le dernier élément.
Je pense que c'est la meilleure réponse si le vecteur n'est pas ordonné. Il ne repose pas sur l'hypothèse qui iterator + indexvous donnera en fait la position de l'itérateur à cet index, ce qui n'est pas le cas de tous les conteneurs itérables. C'est également une complexité constante au lieu d'être linéaire en tirant parti du pointeur arrière.
theferrit32
1
Cela doit totalement être ajouté à la bibliothèque standard au fur unordered_removeet à mesure unordered_remove_ifque cela n'a pas été le cas et que je l'ai manqué, ce qui se produit de plus en plus ces jours-ci :)
Will Crawford
Si suggérerait d'utiliser l'affectation de déplacement ou l'échange au lieu d'une affectation de copie.
Carsten S
std::removeréorganise le conteneur pour que tous les éléments à supprimer soient à la fin, pas besoin de le faire manuellement comme ceci si vous utilisez C ++ 17.
keith
@keith comment ça std::removeaide? cppreference affirme que même en C ++ 17, toutes les removesurcharges nécessitent un prédicat et aucune ne prend d'index.
Paul Du Bois
4
Si vous travaillez avec de grands vecteurs (taille> 100 000) et que vous souhaitez supprimer de nombreux éléments, je recommanderais de faire quelque chose comme ceci:
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;}
Le code prend chaque nombre dans vec qui ne peut pas être divisé par 3 et le copie dans vec2. Ensuite, il copie vec2 dans vec. C'est assez rapide. Pour traiter 20 000 000 éléments, cet algorithme ne prend que 0,8 s!
J'ai fait la même chose avec la méthode d'effacement, et cela prend beaucoup de temps:
vous effacerez le nième élément du vecteur mais lorsque vous effacerez le deuxième élément, tous les autres éléments du vecteur seront décalés et la taille du vecteur sera -1. Cela peut être un problème si vous parcourez le vecteur car la taille du vecteur () diminue. Si vous avez un problème comme celui-ci, le lien proposé suggère d'utiliser l'algorithme existant dans la bibliothèque C ++ standard. et "supprimer" ou "supprimer_si".
Les réponses précédentes supposent que vous avez toujours un index signé. Malheureusement, les std::vectorutilisations size_typepour l'indexation, etdifference_type pour l'arithmétique des itérateurs, donc ils ne fonctionnent pas ensemble si "-Wconversion" et amis sont activés. C'est une autre façon de répondre à la question, tout en étant capable de gérer à la fois signé et non signé:
voici une autre façon de le faire si vous voulez supprimer un élément en le trouvant avec sa valeur dans vector, il vous suffit de le faire sur vector.
vector<int> ar(n);
ar.erase(remove(ar.begin(), ar.end()),(place your value here from vector array));
C'est très non portable; cela fonctionnera avec libstdc ++, mais pas libc ++ et pas avec MSVC. vector<int>::iteratorn'est pas nécessairement le même queint *
Marshall Clow
2
C'est dégoûtant, je pense que je vais changer libstdc ++ pour l'empêcher de fonctionner.
Réponses:
Pour supprimer un seul élément, vous pouvez faire:
Ou, pour supprimer plusieurs éléments à la fois:
la source
operator+
n'est pas nécessairement défini pour les itérateurs sur d'autres types de conteneurs, commelist<T>::iterator
(vous ne pouvez pas le fairelist.begin() + 2
sur unstd::list
, vous devez l'utiliserstd::advance
pour cela)std::find_if
La méthode d'effacement sur std :: vector est surchargée, il est donc probablement plus clair d'appeler
lorsque vous ne souhaitez effacer qu'un seul élément.
la source
vec.begin()
ce qui est valide.vec.erase(0)
cela ne fonctionne pas, maisvec.erase(vec.begin()+0)
(ou sans +0) le fait. Sinon, je ne reçois aucun appel de fonction correspondant, c'est pourquoi je suis venu icivec.erase(0)
peut en fait se compiler s'il0
arrive d'être interprété comme la constante du pointeur nul ...la source
template <typename T> void remove(std::vector<T>& vec, size_t pos) { vec.erase(vec.begin + pos); }
je ne dis pas que c'est mieux, simplement en demandant par intérêt personnel et en retournant le meilleur résultat que cette question pourrait obtenir.vector<T>::iterator
est un itérateur à accès aléatoire, votre version est correcte et peut-être un peu plus claire. Mais la version publiée par Max devrait fonctionner très bien si vous changez le conteneur en un autre qui ne prend pas en charge les itérateurs à accès aléatoireLa
erase
méthode sera utilisée de deux manières:Effacement d'un seul élément:
Effacement d'une gamme d'éléments:
la source
En fait, la
erase
fonction fonctionne pour deux profils:Suppression d'un seul élément
Suppression d'une gamme d'éléments
Puisque std :: vec.begin () marque le début du conteneur et si nous voulons supprimer le ième élément de notre vecteur, nous pouvons utiliser:
Si vous regardez attentivement, vec.begin () n'est qu'un pointeur vers la position de départ de notre vecteur et l'ajout de la valeur de i augmente le pointeur à la position i, nous pouvons donc accéder au pointeur vers le ième élément en:
On peut donc écrire:
la source
Si vous avez un vecteur non ordonné, vous pouvez profiter du fait qu'il n'est pas ordonné et utiliser quelque chose que j'ai vu de Dan Higgins au CPPCON
Étant donné que l'ordre des listes n'a pas d'importance, prenez simplement le dernier élément de la liste et copiez-le par-dessus l'élément que vous souhaitez supprimer, puis sautez et supprimez le dernier élément.
la source
iterator + index
vous donnera en fait la position de l'itérateur à cet index, ce qui n'est pas le cas de tous les conteneurs itérables. C'est également une complexité constante au lieu d'être linéaire en tirant parti du pointeur arrière.unordered_remove
et à mesureunordered_remove_if
que cela n'a pas été le cas et que je l'ai manqué, ce qui se produit de plus en plus ces jours-ci :)std::remove
réorganise le conteneur pour que tous les éléments à supprimer soient à la fin, pas besoin de le faire manuellement comme ceci si vous utilisez C ++ 17.std::remove
aide? cppreference affirme que même en C ++ 17, toutes lesremove
surcharges nécessitent un prédicat et aucune ne prend d'index.Si vous travaillez avec de grands vecteurs (taille> 100 000) et que vous souhaitez supprimer de nombreux éléments, je recommanderais de faire quelque chose comme ceci:
Le code prend chaque nombre dans vec qui ne peut pas être divisé par 3 et le copie dans vec2. Ensuite, il copie vec2 dans vec. C'est assez rapide. Pour traiter 20 000 000 éléments, cet algorithme ne prend que 0,8 s!
J'ai fait la même chose avec la méthode d'effacement, et cela prend beaucoup de temps:
la source
Pour supprimer un élément, utilisez la méthode suivante:
Pour une vue d' ensemble plus large, vous pouvez visiter: http://www.cplusplus.com/reference/vector/vector/erase/
la source
Je suggère de lire ceci car je crois que c'est ce que vous recherchez.https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom
Si vous utilisez par exemple
vous effacerez le nième élément du vecteur mais lorsque vous effacerez le deuxième élément, tous les autres éléments du vecteur seront décalés et la taille du vecteur sera -1. Cela peut être un problème si vous parcourez le vecteur car la taille du vecteur () diminue. Si vous avez un problème comme celui-ci, le lien proposé suggère d'utiliser l'algorithme existant dans la bibliothèque C ++ standard. et "supprimer" ou "supprimer_si".
J'espère que cela a aidé
la source
Les réponses précédentes supposent que vous avez toujours un index signé. Malheureusement, les
std::vector
utilisationssize_type
pour l'indexation, etdifference_type
pour l'arithmétique des itérateurs, donc ils ne fonctionnent pas ensemble si "-Wconversion" et amis sont activés. C'est une autre façon de répondre à la question, tout en étant capable de gérer à la fois signé et non signé:Ôter:
Prendre:
la source
voici une autre façon de le faire si vous voulez supprimer un élément en le trouvant avec sa valeur dans vector, il vous suffit de le faire sur vector.
cela supprimera votre valeur d'ici. Merci
la source
Que dis-tu de ça?
la source
le moyen le plus rapide (pour programmer des concours par complexité temporelle () = constante)
peut effacer 100M d'élément en 1 seconde;
et le plus lisible:
vec.erase(vec.begin() + pos);
la source
vector<int>::iterator
n'est pas nécessairement le même queint *