Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
2821 connectés 

  FORUM HardWare.fr
  Programmation
  C++

  [C++] STL Vector : Suppression d'un ième élément

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

[C++] STL Vector : Suppression d'un ième élément

n°1142314
Slayne
Yaouchhh
Posté le 06-07-2005 à 16:18:41  profilanswer
 

J'ai l'habitude de m'en sortir différemment, mais voila, j'ai ce cas qui se pose et je ne trouve pas de solution pas trop crade.
C'est pourtant tout con : je veux supprimer un certain nombre d'élément d'un vector, et la seule chose que je sais sur les éléments à supprimer de ce vector, c'est leur position.
Pas de bol, erase ne prend en paramètre qu'un iterator. Comment je peux m'en sortir du coup avec cette fonction ou une autre ?
 
Merci  :jap:

mood
Publicité
Posté le 06-07-2005 à 16:18:41  profilanswer
 

n°1142410
Harkonnen
Modérateur
Un modo pour les bannir tous
Posté le 06-07-2005 à 17:25:10  profilanswer
 

avec la méthode find() tu recherches ton élément, puis tu l'effaces

Code :
  1. vector<gnagna> u;
  2. vector<gnagna>::iterator it = find( u.begin(), u.end(), "prout" );
  3. u.erase(it);


---------------
J'ai un string dans l'array (Paris Hilton)
n°1142417
Slayne
Yaouchhh
Posté le 06-07-2005 à 17:29:59  profilanswer
 

C'était un peu ce que j'entendais par "pas trop crade", c'est la seule solution que j'ai trouvé jusqu'à maintenant.
 
Utiliser find pour effacer des éléments dont on connait la position, c'est assez lourd :/
 
Merci quand même, si tu as d'autres idées n'hésites pas :)

n°1142428
Taz
bisounours-codeur
Posté le 06-07-2005 à 17:39:22  profilanswer
 

std::remove(v.begin(), v.end(), "blah" );

n°1142443
Slayne
Yaouchhh
Posté le 06-07-2005 à 17:53:24  profilanswer
 

Taz a écrit :

std::remove(v.begin(), v.end(), "blah" );


 
Idem, ça fera une recherche du début à la fin :/
Enfin bon tant pi, si vous connaissez pas, c'est que ça n'existe probablement pas. Je vais chercher pour une solution différente  alors.

n°1142445
Harkonnen
Modérateur
Un modo pour les bannir tous
Posté le 06-07-2005 à 17:54:49  profilanswer
 

en même temps, pour trouver l'élément précis d'un tableau, faut le parcourir avant hein [:petrus75]


---------------
J'ai un string dans l'array (Paris Hilton)
n°1142446
Taz
bisounours-codeur
Posté le 06-07-2005 à 17:55:39  profilanswer
 

ben ouais ...
 
si tu veux supprimer une plage, tu as les fonctions membres erase .... RTFM

n°1142472
LordHarryP​otter
Posté le 06-07-2005 à 18:24:24  profilanswer
 

Code :
  1. vector<gnagna> u;
  2. int position = 10 ;
  3. vector<gnagna>::iterator it = u.begin()+position;
  4. u.erase(it);


n°1142630
Slayne
Yaouchhh
Posté le 06-07-2005 à 20:53:40  profilanswer
 

Harkonnen a écrit :

en même temps, pour trouver l'élément précis d'un tableau, faut le parcourir avant hein [:petrus75]


 
C'est effectivement ce que je fais, je parcours le vector, je prends la position des éléments qui me vont.
La difficulté, c'est que je ne peux pas traiter les éléments avant de tous les connaitre, c'est à dire après avoir parcouru la totalité du vector.  
 

LordHarryPotter a écrit :

Code :
  1. vector<gnagna> u;
  2. int position = 10 ;
  3. vector<gnagna>::iterator it = u.begin()+position;
  4. u.erase(it);



 
Je vais tester ça, j'avais un doute que ça fonctionne dans tous les cas mais pourquoi pas.
Merci  :jap:

n°1142663
el muchach​o
Comfortably Numb
Posté le 06-07-2005 à 21:14:31  profilanswer
 

Si tu dois souvent effectuer des suppressions de ton container, il faut commencer à te demander si vector est le plus adapté à ton utilisation.

mood
Publicité
Posté le 06-07-2005 à 21:14:31  profilanswer
 

n°1142672
Kristoph
Posté le 06-07-2005 à 21:22:03  profilanswer
 

Slayne a écrit :

C'est effectivement ce que je fais, je parcours le vector, je prends la position des éléments qui me vont.
La difficulté, c'est que je ne peux pas traiter les éléments avant de tous les connaitre, c'est à dire après avoir parcouru la totalité du vector.  
 
 
 
Je vais tester ça, j'avais un doute que ça fonctionne dans tous les cas mais pourquoi pas.
Merci  :jap:


Il y a un algorithme qui fait ça automatiquement : remove_if. Surtout ne pas oublier l'appel à erase après bien sur.

n°1142694
LordHarryP​otter
Posté le 06-07-2005 à 21:49:44  profilanswer
 

Et pour quoi ne récupère tu pas des iterateurs sur ton vecteur en gros t'as un vecteur d'itérateur de ton vecteur niania contenant les positions du vecvteur à supprimer :
 

Code :
  1. vector<gnagna> u;
  2. vector<vector<gnagn>::iterator> vect_pos ;
  3. for (vector<vector<gnagn>::iterator>::iterator it = vect_pos.begin() ;
  4.         it < vect_pos.end() ; ++it)
  5. {
  6.   u.erase(*it);
  7. }


 
Ouaou un vecteur de vecteur d'itérateur et un itérateur de vecteur d'itérateur de vecteur : cool bébé

n°1142717
sankukai8
Posté le 06-07-2005 à 22:29:32  profilanswer
 

vector<truc> vect;
// nieme element a effacer dans vect
int n;
vect.erase(vect.begin()+n);
voilou! :bounce:  :bounce:


Message édité par sankukai8 le 07-07-2005 à 08:08:11
n°1142838
_darkalt3_
Proctopathe
Posté le 07-07-2005 à 08:27:22  profilanswer
 

[:drapal]


---------------
Töp of the plöp
n°1142895
theshockwa​ve
I work at a firm named Koslow
Posté le 07-07-2005 à 09:47:01  profilanswer
 


 
Sauf que normalement, le premier appel à erase invalide tes autres itérateurs et le comportement de ton algo n'est pas vraiment sur, non ?
 
Edit : typo
Edit 2 : La solution la plus adaptée me semble toujours d'effacer les éléments (s'ils sont contigus) avec un erase() ou alors de passer par un remove_if et un functor adapté (qui embarquerait la liste des indices, par exemple, et incrémenterait son compteur interne à chaque appel de la fonction de comparaison)


Message édité par theshockwave le 07-07-2005 à 09:53:10
n°1142914
theshockwa​ve
I work at a firm named Koslow
Posté le 07-07-2005 à 10:01:45  profilanswer
 

Je suggèrerais plutôt quelque chose de ce genre là :

Code :
  1. #include <vector>
  2. #include <set>
  3. #include <algorithm>
  4. class Elem {};
  5. class IndexRemover{
  6.   const std::set<size_t> &_indices;
  7.   size_t _i;
  8. public:
  9.   IndexRemover(const std::set<size_t> &indices) : _indices(indices), _i(0) {};
  10.   bool operator () (const Elem & ) {
  11.     return _indices.find(_i++) != _indices.end();
  12.   };
  13. };
  14. int main() {
  15. std::vector<Elem> vect;
  16. std::set<size_t> indices;
  17. std::remove_if(vect.begin(), vect.end(), IndexRemover(indices));
  18. return 0;
  19. }


 
Edit : typo ( je me bats un peu avec mon clavier :D )


Message édité par theshockwave le 07-07-2005 à 10:02:21
n°1143371
sankukai8
Posté le 07-07-2005 à 15:58:25  profilanswer
 

2 cas sont possibles
les elements du vecteur devant etre supprimés peuvent etre :
  1/ rangés dans l'ordre croissant directement dans un tableau
     dans ce cas on peut faire:

Code :
  1. vector<truc> vect     // ton vecteur
  2. vector<int> position; // les positions a enlever dans le vect dans l'ordre croissant
  3. while (position.size()!=0) {
  4.                            vect.erase(vect.begin()+position.back());
  5.                            position.pop_back();
  6.                           }


  2/ si les positions ne sont pas trouvées directement dans l'ordre croissant,
     alors il faut les mettre. c'est important car comme on efface d'abord le dernier,
la position relative des précedents reste la meme.
 
je ne sait pas si on peut considerer ca comme "propre", mais j'ai vérifié, ca marche
l'avantage, c'est que les positions ne sont pas necessairement une plage!!


Message édité par sankukai8 le 08-07-2005 à 08:00:32
n°1143407
Taz
bisounours-codeur
Posté le 07-07-2005 à 16:24:43  profilanswer
 

vect.erase(vect.begin()+position.back()); ????????

n°1143444
Slayne
Yaouchhh
Posté le 07-07-2005 à 16:54:57  profilanswer
 

sankukai8 a écrit :


je ne sait pas si on peut considerer ca comme "propre", mais j'ai vérifié, ca marche


 
C'est effectivement la solution que j'ai adopté, mixé avec l'une des réponses précédentes ...
J'ai fait un vecteur d'itérateur, et j'ai effacé mes éléments dans l'ordre décroissant pour que mes itérateurs soient toujours valable même après suppression.
 
En tout cas c'est vraiment peu pratique, il y a surement des containers mieux adapter que les vector ou map pour faire ce genre de chose, mais le programmeur précédent avait commencé sur ça et j'ai pas le temps de tout refaire de A à Z :/

n°1143908
sankukai8
Posté le 08-07-2005 à 08:08:12  profilanswer
 

Taz a écrit :

vect.erase(vect.begin()+position.back()); ????????


 
vect est le vecteur dont on veut effacer certaine entrée
 
position est un vecteur d'entiers dont les entrées situent  
la position (d'ou son nom) des entrées a effacer dans vect
 :pfff:  
sachant que vect.begin() renvoie un iterateur sur la premiere  
position de vect (c'est a dire 0) et que position.back() renvoie
la derniere entrée du vecteur position (un entier), et que l'on peut
"ajouter" un entier et un iterateur, ce qui fournit un iterateur,
alors on a
 
vect.begin()+position.back() qui donne un iterateur egale a la position
de la derniere entrée de vect a effacer.
par consequent vect.erase(vect.begin()+position.back()) efface cette
entrée la   :pt1cable:

n°1143909
sankukai8
Posté le 08-07-2005 à 08:10:43  profilanswer
 

n'est il pas possible d'effacer directement les entrées de ton vecteur
lorsque tu testes si elle est a garder ou pas plutot que de prendre sa position pour
ensuite effacer cette position?
suis-je clair???

n°1144030
Taz
bisounours-codeur
Posté le 08-07-2005 à 10:12:02  profilanswer
 

non. tu peux additioner vector<>::value_type et vector<>::iterator si vector<>::value_type est implicitement convertible en entier. Mais c'est dégueulasse. Quand au résultat, je vois pas. si v.back() == -1, tu erase sur un itérateur invalide. Bref sémantiquement ça ne veut rien dire. Utilise end/rend/...

n°1144037
Slayne
Yaouchhh
Posté le 08-07-2005 à 10:15:17  profilanswer
 

sankukai8 a écrit :

n'est il pas possible d'effacer directement les entrées de ton vecteur
lorsque tu testes si elle est a garder ou pas plutot que de prendre sa position pour
ensuite effacer cette position?
suis-je clair???


 
2 choses :  
- Je suis pas sûr qu'en effaçant des objets dans mon vecteur pendant ma boucle for, mon iterateur ne fasse pas n'importe quoi. J'ai fait quelques tests avec des maps, faire un erase pendant qu'on parcoure la map, c'est pas maitrisable :/ Dans un vector ça a l'air de marcher avec des bidouilles genre iterateur--.
 
- Non je ne peux pas faire comme tu dis, car quand je parcoure mon vecteur, je prends les éléments qui me plaisent, mais s'il y en a qui me plaisent mieux, je les prends à la place des premiers. Là c'est moi qui suis peut être pas très clair.  
Enfin pour etre plus clair, j'ai un pixel p0, je parcoure un vecteur de pixel v dans lequel je cherche tous les pixels qui sont à une distance minimale de p0.

n°1144063
Lam's
Profil: bas.
Posté le 08-07-2005 à 10:30:35  profilanswer
 

Slayne a écrit :

2 choses :  
- Je suis pas sûr qu'en effaçant des objets dans mon vecteur pendant ma boucle for, mon iterateur ne fasse pas n'importe quoi. J'ai fait quelques tests avec des maps, faire un erase pendant qu'on parcoure la map, c'est pas maitrisable :/


Si, la méthode erase est faite pour.

Code :
  1. map<string, string> trucmuche;
  2. map<string, string>::iterator it = trucmuche.begin();
  3. while (it!=trucmuche.end())
  4. {
  5.   if (...)
  6.     it=trucmuche.erase(it);
  7.   else
  8.     ++it;
  9. }


n°1144080
Slayne
Yaouchhh
Posté le 08-07-2005 à 10:41:15  profilanswer
 

void erase(iterator pos) :)
Et si on vire le "it=" devant, ça compile mais le résultat, c'est pas trop ça :/
Par contre le erase de vector marche super bien  :o


Message édité par Slayne le 08-07-2005 à 10:50:05
n°1144097
Lam's
Profil: bas.
Posté le 08-07-2005 à 10:50:33  profilanswer
 

Slayne a écrit :

void erase(iterator pos) :)
Et si on vire le "it=" devant, ça compile mais le résultat, c'est pas trop ça :/
Par contre le erase de vector marche super bien  :o


Tu compiles avec quoi ?  Et tu utilises quelle référence pour les signatures ?
edit: parce que même VS6 utilise une STL qui renvoie un itérateur, conforme à ça: http://www.dinkumware.com/manuals/ [...] map::erase
ou à ça:
http://msdn.microsoft.com/library/ [...] perase.asp


Message édité par Lam's le 08-07-2005 à 10:51:58
n°1144120
sankukai8
Posté le 08-07-2005 à 11:07:48  profilanswer
 

Taz a écrit :

non. tu peux additioner vector<>::value_type et vector<>::iterator si vector<>::value_type est implicitement convertible en entier. Mais c'est dégueulasse. Quand au résultat, je vois pas. si v.back() == -1, tu erase sur un itérateur invalide. Bref sémantiquement ça ne veut rien dire. Utilise end/rend/...


 
 
 
v.back()!=-1 car il y a le test dans le while!
position est un vecteur d'entier, donc pas de conversion implicite vers un entier!
 
il est possible que cela soit dégueulasse comme tu dis,meme si je ne vois pas bien pourquoi (je ne suis pas un pro du c++) mais en tout cas cela a le mérite de fonctionner sans probleme, et les positions a effacer ne sont pas un range

Code :
  1. #include <iostream>
  2. #include <stdlib.h>
  3. #include <vector>
  4. using namespace std;
  5. int main(int argc, char *argv[])
  6. {
  7.   vector<int> vect(7);
  8.   vector<int> position(3);
  9.   for (int i=0;i<7;i++) vect[i]=i;
  10.   position[0]=2;
  11.   position[1]=4;
  12.   position[2]=5;
  13.   cout<<"vecteur initial\n";
  14.   for (int i=0;i<7;i++) cout<<vect[i]<<"\n";
  15.   while (position.size()!=0) {
  16.                            vect.erase(vect.begin()+position.back());
  17.                            position.pop_back();
  18.                            }
  19.   cout<<"apres elimination de 2 4 et 5\n";
  20.   for (int i=0;i<vect.size();i++) cout<<vect[i]<<"\n";
  21.   system("PAUSE" );
  22.   return 0;
  23. }


lorsque je compile cela avec dev c++ j'obtient a l'ecran:
 
vecteur initial
0
1
2
3
4
5
6
apres elimination de 2 4 et 5
0
1
3
6


Message édité par sankukai8 le 08-07-2005 à 11:15:25
n°1144135
Slayne
Yaouchhh
Posté le 08-07-2005 à 11:17:02  profilanswer
 

Lam's a écrit :

Tu compiles avec quoi ?  Et tu utilises quelle référence pour les signatures ?
edit: parce que même VS6 utilise une STL qui renvoie un itérateur, conforme à ça: http://www.dinkumware.com/manuals/ [...] map::erase
ou à ça:
http://msdn.microsoft.com/library/ [...] perase.asp


 
J'utilise g++ sous une fedora 4, donc plutot récent. Et le "void erase( iterator)", je le sors directement du site de la STL hein  :D  
Enfin google groupes est mon ami, une solution est :
 

Code :
  1. map<string, string> trucmuche;
  2. map<string, string>::iterator it = trucmuche.begin();
  3. while (it!=trucmuche.end())
  4. {
  5.    if (...)
  6.      trucmuche.erase(it++);
  7.     else
  8.       ++it;
  9. }


 
Ca marche aussi dans une boucle for, en remplacant le it++ par it--, et en supprimant le else. => Probleme avec le 1er element


Message édité par Slayne le 08-07-2005 à 11:25:10
n°1144141
theshockwa​ve
I work at a firm named Koslow
Posté le 08-07-2005 à 11:20:57  profilanswer
 

Elle ne vous plait pas, ma méthode avec remove_if et functor ? :o

n°1144143
Slayne
Yaouchhh
Posté le 08-07-2005 à 11:23:14  profilanswer
 

theshockwave a écrit :

Elle ne vous plait pas, ma méthode avec remove_if et functor ? :o


 
Si mais c'etait pour l'autre probleme, là le nouveau probleme c'est la suppression d'element dans une map pendant qu'on parcoure la map  :o

n°1144149
Taz
bisounours-codeur
Posté le 08-07-2005 à 11:26:38  profilanswer
 

bon je laisse béton vos bordels, c'est nimp

n°1144150
slash33
Posté le 08-07-2005 à 11:27:47  profilanswer
 

Pour les suppressions "à la volée" je parcours le conteneur à l'envers. Je ne sais pas trop si c'est applicable aux conteneurs de la STL, puisque je m'en sert peux - full MFC ;)

n°1144177
Lam's
Profil: bas.
Posté le 08-07-2005 à 11:41:27  profilanswer
 

Slayne a écrit :

J'utilise g++ sous une fedora 4, donc plutot récent. Et le "void erase( iterator)", je le sors directement du site de la STL hein  :D  


D'une part, qu'entends-tu par "le site de la STL" ?
Et d'autre part, tu me confirmes donc que ce code-ci ne compile pas avec ta version de g++:

Code :
  1. #include <map>
  2. #include <string>
  3. using std::map;
  4. using std::string;
  5. void m()
  6. {
  7. map<string, string> trucmuche;
  8. map<string, string>::iterator it = trucmuche.begin();
  9. while (it!=trucmuche.end())
  10. {
  11.     if (true)
  12.       it = trucmuche.erase(it); // edit
  13.      else
  14.        ++it;
  15. }
  16. }


Message édité par Lam's le 08-07-2005 à 12:22:04
n°1144243
Slayne
Yaouchhh
Posté le 08-07-2005 à 12:18:20  profilanswer
 

1 -> http://www.sgi.com/tech/stl/
 
2 -> Si si, celui ci compilera (tu n'as pas ecrit it = trucmuche.erase(it); cette fois ci). Mais il ne fera pas du tout ce qu'on attend qu'il fasse (mauvais placement de l'iterateur). Sur les groups on peut voir comme solution "trucmuche.erase(it++); " en gardant identique le reste de ton code.


Message édité par Slayne le 08-07-2005 à 12:18:31
n°1144252
Lam's
Profil: bas.
Posté le 08-07-2005 à 12:21:50  profilanswer
 

Slayne a écrit :

1 -> http://www.sgi.com/tech/stl/
 
2 -> Si si, celui ci compilera (tu n'as pas ecrit it = trucmuche.erase(it); cette fois ci). Mais il ne fera pas du tout ce qu'on attend qu'il fasse (mauvais placement de l'iterateur). Sur les groups on peut voir comme solution "trucmuche.erase(it++); " en gardant identique le reste de ton code.


Oui, c'est effectivement une des 2 solutions.  
 
J'ai oublié le "it=" devant mon erase, mais pourrais tu essayer de compiler ce bout de code ? (avec le it=" en début de ligne). Ca passe nickel sous Visual Studio, sous Forte, sous Comeau, et sous gcc 2.9 et 3.0 si je ne dis pas de bétises...
 
Quand au site de sgi, il est vraiment vieux et plus du tout maintenu (il date de Juin 2000)

n°1144260
Slayne
Yaouchhh
Posté le 08-07-2005 à 12:29:11  profilanswer
 

Voila le message d'erreur  

Citation :


test_map.cpp: In function ‘int main()’:
test_map.cpp:84: erreur: no match for ‘operator=’ in ‘it = trucmuche. std::map<_Key, _Tp, _Compare, _Alloc>::erase [with _Key = std::string, _Tp = std::string, _Compare = std::less<std::string>, _Alloc = std::allocator<std::pair<const std::string, std::string> >](it)’
/usr/lib/gcc/i386-redhat-linux/4.0.0/../../../../include/c++/4.0.0/bits/stl_tree.h:152: note: candidats sont: std::_Rb_tree_iterator<std::pair<const std::string, std::string> >& std::_Rb_tree_iterator<std::pair<const std::string, std::string> >::operator=(const std::_Rb_tree_iterator<std::pair<const std::string, std::string> >& )


 
Et merci pour l'info sur le site, je savais pas ... mais y'a une doc maintenu a jour ?
 
EDIT : "version gcc 4.0.0"


Message édité par Slayne le 08-07-2005 à 12:33:00
n°1144318
HelloWorld
Salut tout le monde!
Posté le 08-07-2005 à 13:32:59  profilanswer
 

std::advance permet d'obtenir un itérateur sur un élément connaisant sa position.

Code :
  1. std::vector<int> myvector( 5 );
  2.     size_t pos = 4;
  3.     std::vector<int>::iterator i = myvector.begin();
  4.     std::advance( i, pos );
  5.     myvector.erase( i );


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
mood
Publicité
Posté le   profilanswer
 


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  C++

  [C++] STL Vector : Suppression d'un ième élément

 

Sujets relatifs
[ACCESS] Récuperer des données avt suppressioncréer un objet d'un element de base de données.
[Batch] Suppression de fichiers et repertoire videSupprimer element d'un Jlist simplement.... GALERE
suppression des fichiers temporaires sous IE[C++] Priority_queue/Vector
Suppression de fichier[MS-DOS]Suppression de fichiers
supprimer un element de tableau en variable de session 
Plus de sujets relatifs à : [C++] STL Vector : Suppression d'un ième élément


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR