Forum Programmation.python Supprimer l'élément en cours d'une liste

Posté par  .
Étiquettes : aucune
0
26
juin
2009
Bonjour,

Je souhaite filtrer les éléments d'une liste avec une boucle for.
Je sais le faire en utilisant les "list comprehension"
maliste = ['abc', 'def', 'testa', 'testaa', 'atest', 'tast']
maliste = [el for el in maliste if 'a' not in el]

--> maliste ne contient plus alors que 'def', le seul élément à ne pas avoir la lettre 'a'.

J'ai du mal à comprendre que
for el in maliste:
if 'a' in el:
maliste.pop(maliste.index(el))
print maliste

Me renvoie
['def', 'testaa', 'tast']
.

Je souhaite éviter de passer par une liste temporaire qui rend le code moins lisible et simplement supprimer l'élément en cours s'il remplit la condition.

Merci pour vos suggestions et bon week-end :-)
  • # Explications

    Posté par  . Évalué à 6.

    On ne modifie pas une liste sur laquelle on est en train d'itérer, sinon tout par en couilles. C'est pour ça que tu obtiens ce résultat. Quand tu va "poper" testa, testaa va se retrouver à sa place et à la prochaine itération, il va passer après. L'élément testaa sera donc passé "à travers" les mailles du filet.

    En passant, tu peux utiliser maliste.remove(el) à la place de ton pop+index.

    Ensuite, tu ne veux pas passer par une liste "temporaire", mais c'est exactement ce que va te faire le premier exemple en utilisant la compréhension de liste : il va créer une nouvelle liste, l'affecter à maliste, et l'ancienne va se faire garbage-collecter car elle n'est plus référencée. Pourtant, c'est très lisible (d'ailleurs, pourquoi ne choisis-tu pas cette solution ?).

    En tous cas, ta manière de penser me fait dire que t'es un habitué du C ou d'un autre langage "bas niveau", et j'ai l'impression que tu essayes de faire la même chose en python : ce n'est pas, selon moi, la bonne approche. Utilise plutôt les manières de faire du langage. Certes, tu ne seras peut-être pas aussi rapide que du C, mais si c'est la rapidité qui t'importe, pourquoi as-tu choisi python ?

    Enfin, pour te montrer qu'on peut aussi faire complètement différent, en fonctionnel :
    filter(lambda x: not 'a' in x, maliste)
    Même si il me semble que Guido a déprécié l'utilisation de map/filter en faveur de la syntaxe "list comprehension".
    • [^] # Re: Explications

      Posté par  . Évalué à 2.

      Merci pour ta réponse, benoar.

      Je souhaite faire cette opération pour le cas où la condition est bien plus complexe que ça et dépend de calculs effectués dans la boucle.

      Ce que je voulais dire par "éviter de passer par une liste temporaire", c'était plutôt dans l'idée "éviter de déclarer une autre liste pour soit l'utiliser comme copie soit faire des append dedans". Que python le fasse tout seul, y a pas de lézard.

      ps: Je ne connais pas le C, python est mon premier vrai langage (en dehors de l'ABAP).
      • [^] # Re: Explications

        Posté par  . Évalué à 3.

        Je souhaite faire cette opération pour le cas où la condition est bien plus complexe que ça et dépend de calculs effectués dans la boucle.
        Et bien tu peux déclarer ta grosse fonction avant, et l'utiliser dans la list comprehension :
        def ma_grosse_fonction(x): # qui renvoie si l'élément est bon / pas bon
        ...
        maliste = [ el for el in maliste if ma_grosse_fonction]


        Ce que je voulais dire par "éviter de passer par une liste temporaire", c'était plutôt dans l'idée "éviter de déclarer une autre liste pour soit l'utiliser comme copie soit faire des append dedans". Que python le fasse tout seul, y a pas de lézard.
        Mouai, ça me permet pas un argument terrible, surtout si c'est pour se mettre à faire des trucs crades. Et puis déjà, rien qu'en voyant que tu utilises la même variable pour désigner deux choses différentes (la liste avant filtrage, et après filtrage), j'ai un feeling un peu "bof bof". Oui, on peut modifier des variables, mais quand elles représentent vraiment deux choses différentes, je préfère en faire deux.

        Et puis tiens, encore une autre manière de faire :
        def mon_traitement(maliste):
        for el in maliste:
        if condition1:
        ....
        continue # l'élément ne respecte pas ma première condition
        if condition2:
        yield el # j'ai envie d'inclure ceux qui respectent la condition 2
        ...

        Qui te permettera de faire, là où tu utilises la liste résultante :
        for el in mon_traitement(maliste):
        # j'utilise les éléments filtrés de maliste

        Tout en effectuant le filtrage au fur et à mesure seulement, pas d'un coup comme tu le fais si tu filtres tout d'abord. C'est utile quand tu as une grosse liste, ou que le traitement de filtrage ferait que ce serait trop lourd de tout faire au début.

        Enfin, je ne connaissais pas l'ABAP, mais ça m'a permis de voir un autre style de programmation ... mais bon, je préfère toujours python !
        • [^] # Re: Explications

          Posté par  . Évalué à 2.

          Bon, les espaces sont pas passés dans le code mais j'espère que c'est compréhensible.
          • [^] # Re: Explications

            Posté par  . Évalué à 2.

            C'est tout à fait compréhensible et je te remercie beaucoup.

            L'ABAP c'est le langage propriétaire de SAP, loin de la souplesse de python (on ne peut pas faire un chemin.split('/')[-1] simplement en ABAP). Mais c'est un autre débat.
            • [^] # Re: Explications

              Posté par  . Évalué à 3.

              (on ne peut pas faire un chemin.split('/')[-1] simplement en ABAP)

              Je suppose que tu voulais dire os.path.basename ? :)

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.