Pouvez-vous m'enrichir d'une m�thode �l�gante pour it�rer sur une liste
priv�e de certains de ses �l�ments ?
La solution que j'emploie actuellement est celle-ci :
>for e in list1 :
> if not e in list2 :
> <instructions>
Elle a le d�savantage de diviser la d�finition de mon ensemble it�r� sur
deux instructions, et d'approfondir inutilement l'indentation.
J'avais envisag� les listes en intention, ce qui me donnait ceci :
>for e in [e for e in list1 if e not in list2]:
> <instructions>
Mais comme vous pouvez l'appr�cier, �a n'a plus grand chose de lisible.
La syntaxe suivante d�riv�e des listes en intention ne fonctionne pas :
>for e in list1 if e not in list2 :
Avez-vous une meilleure solution � me proposer ?
Tu peux essayer :
for e in filter (<fonction>, list1):
<instruction>
Avec <fonction> qui peut �tre une fonction bool�enne qui fasse ton
filtrage (si cette fonction existe d�j�) ou une lambda expression si tu
ne veux pas surcharger ton espace de noms.
Ex:
for e in filter (lambda x: x not in list2, list1):
<instruction>
Le gain n'est quand m�me pas �norme par rapport � la syntaxe initiale.
for e in list1:
if e in list2: continue
<instructions-sans-approfondir-inutilement-l-indentation>
J'adore faire des trucs comme �a dans les boucles :
on peut mettre plein de tests en d�but de boucle, pour ignorer toute une
s�rie de cas, sans approfondir inutilement...
Ca �vite parfois de se retrouver avec le bloc d'instructions "utiles"
perdu dans une 3eme, 4eme niveau d'indentation, ce qui n'est pas
forc�ment plus lisible que quelques instructions continue bien
identifi�es en d�but de boucle.
Mais elle a l'avantage d'ᅵtre maintenable sans risque de casser
vicieusement un truc qui marche. Je suis revenu de mon ᅵpoque "tout
doiot tenir sur une seule ligne" qui me gᅵnᅵrait des trucs qui me
prenaient dix minutes ᅵ dᅵtricoter pour modifier par exemple un test.
Les deux trucs proposᅵs par Alain BARTHE sont parfaits sur le plan de
la maintenabilitᅵ.
> J'avais envisagᅵ les listes en intention, ce qui me donnait ceci :
> >for e in [e for e in list1 if e not in list2]:
> > <instructions>
>
> Mais comme vous pouvez l'apprᅵcier, ᅵa n'a plus grand chose de lisible.
Si vous trouvez ᅵa illisible, le problᅵme est peut-ᅵtre chez vous ;-)
Vous pouvez compacter, et pour moi ᅵa reste trᅵs lisible:
[instructions(_) for _ in list1 if _ not in list2]
ou
[instructions(_) for _ in filter(<fonction>, list1)]
Selon ce que fait <instructions> vous codez une fonction ou utilisez un
lambda. Vous pouvez aussi regarder du cotᅵ de map et reduce.
Je me rᅵpᅵte, j'ai perdu pas mal de temps ᅵ chercher ᅵ coder ᅵlᅵgant.
Rᅵsultat, je perdais du temps, ce n'ᅵtait *pas* ᅵlᅵgant parce
qu'illisible, bref, j'ai changᅵ mon fusil d'ᅵpaule et je vais au plus
rapide et naturel. A vous de voir...
> La syntaxe suivante dᅵrivᅵe des listes en intention ne fonctionne pas :
> >for e in list1 if e not in list2 :
>
> Avez-vous une meilleure solution ᅵ me proposer ?
--
Pierre Maurette
> Bonjour,
>
> Pouvez-vous m'enrichir d'une méthode élégante pour itérer sur une liste
> privée de certains de ses éléments ?
>
> La solution que j'emploie actuellement est celle-ci :
> >for e in list1 :
> > if not e in list2 :
> > <instructions>
>
Est-ce une situation où il est possible d'utiliser les ensembles
("sets") ?
Dans un cas simple, j'ai remplacé :
l5 = range(5, 1000, 5)
l3 = range(3, 1000, 3)
l = l3
for i in l5:
if not i in l3:
l.append(i)
par :
s5 = set(range(5, 1000, 5))
s3 = set(range(3, 1000, 3))
s = s3 | s5
avec un bon gain d'efficacité.
Bruno.
Je pense que l'opᅵrateur, c'est - et non | (union).
on peut penser ᅵ
for e in set(list1) - set(list2):
etc.
Mais avec les set on change d'algo. Mᅵme sans parler de l'ordre. Dans
la question on ᅵliminait toutes les occurences d'un ᅵlᅵment s'il ᅵtait
prᅵsent dans list2, mais on traitait autant de fois les autres qu'ils
ᅵtaient dans list1. Avec les set, on ᅵlimine les doublons (et plus).
> avec un bon gain d'efficacitᅵ.
Sᅵr ?
--
Pierre Maurette
> PIGUET Bruno, le 06/11/2009 a écrit :
>> Est-ce une situation où il est possible d'utiliser les ensembles
>> ("sets") ?
[Je zappe les remarques pertinentes de Pierre, en particulier sur
l'ordre et les doublons.]
>> avec un bon gain d'efficacité.
>
> Sûr ?
Sûr. Au moins un facteur N/log(N) probablement, où N est la taille du
deuxième ensemble. Sauf cas très particulier.
-- Alain.
> Mais avec les set on change d'algo.
C'est pour ça que j'ai commencé mon message par :
"Est-ce une situation où il est possible d'utiliser les ensembles
("sets") ?"
Le premier bout de code que j'ai recopié était une façon de faire une
liste unique en disant "si un nouvel élément n'est pas (déjà) dans la
liste, je l'ajoute (append)". Donc l'opérateur de set correspondant était
bien "|".
Mais cette transformation d'exclusion en union n'est pas forcément
celui que souhaitais l'OP. D'où mon introduction prudente.
> > avec un bon gain d'efficacité.
>
> Sûr ?
Le bon benchmarking est un art difficile. Sur mon cas, et ce que j'ai pu
en mesurer, oui.
Bruno.
Dᅵsolᅵ. Je ne pensais pas que vous ᅵtiez aussi ᅵloignᅵ que ᅵa du
problᅵme de l'OP, et comme souvent j'ai lu en diagonale et ce que je
*voulais* lire, ᅵ savoir:
l5 = range(5, 1000, 5)
l3 = range(3, 1000, 3)
l = [] #et non l = l3 !!!
for i in l5:
if not i in l3:
l.append(i)
ce qui fait ce que veut l'OP, aux doublons prᅵs bien entendu.
Ce que vous faisiez, c'est la liste des multiples - non nuls - de 3 et
de 5, en faisant attention ᅵ ne pas inclure deux fois les multiples
communs, donc les multiples de 15.
C'est effectivement complᅵtement un problᅵme d'ensemble. Le gain de
performance reste ᅵnorme mᅵme en faisant
s = sorted(list(s3 | s5))
Remarque: par rapport ᅵ la solution bourrin, on est - dans certaines
conditions de test - ~10 fois plus rapide en faisant:
l5 = range(5, 1000, 5)
l3 = range(3, 1000, 3)
l15 = range(15, 1000, 15)
l = l3
for i in l5:
if not i in l15:
l.append(i)
mais ᅵa reste au moins 5 fois plus lent qu'avec les ensembles, mᅵme en
convertissant le rᅵsultat en liste triᅵe.
>>> avec un bon gain d'efficacitᅵ.
>>
>> Sᅵr ?
>
> Le bon benchmarking est un art difficile. Sur mon cas, et ce que j'ai pu
> en mesurer, oui.
J'ai mesurᅵ ᅵgalement, quand le problᅵme est adaptᅵ aux ensembles, la
diffᅵrence est monstrueuse, effectivement. Il est d'ailleurs clair que
set(range()) est traitᅵ spᅵcifiquement, et non pas comme
set(listequelconque()).
--
Pierre Maurette
Les deux solutions que vous proposez me paraissent tr�s lisibles et
explicites, ce qui est en quelque sorte mon crit�re supr�me d'�l�gance.
Je vois par ailleurs que les deux ont �t� propos�es en r�ponse � une
proposition de changement de la syntaxe de for sur la ML python-dev :
http://mail.python.org/pipermail/python-dev/2008-May/079556.html
http://mail.python.org/pipermail/python-dev/2008-May/079567.html
C'est le genre d'enrichissement que j'�tais venu chercher, merci beaucoup :)
De rien :)