OVH Cloud OVH Cloud

list

5 réponses
Avatar
Youssef Mesri
Comment je peux supprimer un element sur deux(par exemple les elements
d'indices impair) dans une list?
J'ai essaye des choses comme cela :

1-
list<double> X;
list<double>::iterator iter;
for (int k=0; k<X.size() ; k++)
{
++iter;
if (!(k%2)) { X.pop_back(); }

}

2- mais je veux avoir une syntaxe de ce type:

for (iter=X.begin(); iter!=X.begin() ; iter++)
{

if (!(k%2)) { X.erase(iter); }

}


mais il marche pas!! j'ai l'impression que l'iterateur est aussi ecrase
parce que l'excution s'interompe des le deuxieme tour de boucle

merci d'avance pour vos reponses

5 réponses

Avatar
Patrick Mézard
Comment je peux supprimer un element sur deux(par exemple les elements
d'indices impair) dans une list?
J'ai essaye des choses comme cela :

1-
list<double> X;
list<double>::iterator iter;
for (int k=0; k<X.size() ; k++)
{
++iter;
if (!(k%2)) { X.pop_back(); }

}


pop_back() enlève le dernier élément du conteneur, indépendamment de
tout itérateur. Cela ne peut donc pas marcher.


2- mais je veux avoir une syntaxe de ce type:

for (iter=X.begin(); iter!=X.begin() ; iter++)
{

if (!(k%2)) { X.erase(iter); }

}


mais il marche pas!! j'ai l'impression que l'iterateur est aussi ecrase
parce que l'excution s'interompe des le deuxieme tour de boucle


Exactement (et ton test de fin de boucle n'est pas bon).
erase(p) détruit l'objet pointé par p invalide l'itérateur "p" et
parfois quelques autres suivant le type du conteneur. Dans le cas d'une
std::list, seul "p" est invalidé. Ton problème est que tu voudrais
continuer à itérer. On peut incrémenter "iter" en postfixe, histoire de
le modifier tout en récupérant la valeur précédente :

for(iter=X.begin(); iter!=X.end(); ++iter)
{
X.erase(iter++);
if(iter==X.end())
break;
}

Suivant l'implémentation de la STL dont tu disposes tu peux aussi
récupérer la valeur de retour du erase() :

for(iter=X.begin(); iter!=X.end(); ++iter)
{
iter = X.erase(iter);
if(iter==X.end())
break;
}

Tu devrais t'intéresser à la notion de validité d'itérateur dans la STL,
tu risques de perdre beaucoup de temps autrement.

--
Patrick Mézard

Avatar
kanze
Patrick Mézard wrote:

[...]
for(iter=X.begin(); iter!=X.end(); ++iter)
{
X.erase(iter++);
if(iter==X.end())
break;
}


Par curiosité : pourquoi le test avec break ? Il me semble qu'il
faut double emploi avec la condition dans le for.

Suivant l'implémentation de la STL dont tu disposes tu peux
aussi récupérer la valeur de retour du erase() :

for(iter=X.begin(); iter!=X.end(); ++iter)
{
iter = X.erase(iter);
if(iter==X.end())
break;
}


Comment ça, suivant l'implémentation ? La fonction erase renvoie
toujours un itérateur sur l'élément qui suivait l'élément
éffacé.

Pour son problème précis :

list<double>::iterator iter = X.begin() ;
while ( iter != X.end() ) {
if ( k % 2 == 0 ) {
iter = X.erase( iter ) ;
// ou : X.erase( iter ++ ) ;
} else {
++ iter ;
}
}

Tu devrais t'intéresser à la notion de validité d'itérateur
dans la STL, tu risques de perdre beaucoup de temps autrement.


Je dirais que le fait qu'il faut s'y intéresser autant fait déjà
perdre beaucoup de temps. Dans les collections pré-norme,
j'éstîmais que le support pour quelque chose comme :

for ( Iterator iter( collection ) ;
! iter.isDone() ;
iter.next() ) {
if ( condition( iter.current() ) ) {
collection.remove( iter ) ;
}
}

était un minimum d'une collection bien conçue. (À vrai dire, je
le crois encore. Avec le corollaire que j'estîme la STL assez
mal conçue.)

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Avatar
Fabien LE LEZ
On 27 Dec 2005 01:59:29 -0800, "kanze" :

Comment ça, suivant l'implémentation ? La fonction erase renvoie
toujours un itérateur sur l'élément qui suivait l'élément
éffacé.


Disons qu'il faut vérifier que l'implémentation utilisée est conforme.
Je connais une SL qui contient std::basic_string<> mais
"void std::list<>::erase()".

Avatar
Patrick Mézard
Patrick Mézard wrote:

[...]

for(iter=X.begin(); iter!=X.end(); ++iter)
{
X.erase(iter++);
if(iter==X.end())
break;
}



Par curiosité : pourquoi le test avec break ? Il me semble qu'il
faut double emploi avec la condition dans le for.


Parce qu'il me semble que (iter!=X.end()) est une précondition à
l'incrémentation de iter.

--
Patrick Mézard


Avatar
kanze
Patrick Mézard wrote:
Patrick Mézard wrote:

[...]

for(iter=X.begin(); iter!=X.end(); ++iter)
{
X.erase(iter++);
if(iter==X.end())
break;
}


Par curiosité : pourquoi le test avec break ? Il me semble
qu'il faut double emploi avec la condition dans le for.


Parce qu'il me semble que (iter!=X.end()) est une précondition
à l'incrémentation de iter.


En effet. J'avais raté le fait que tu incrémentes deux fois à
chaque passage. (Je ne pensais pas tellement au cas précis de
supprimer un élément sur deux, mais au cas plus général de
supprimer un élément dans une boucle.)

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34