IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

break et list comprehension ?


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert Avatar de PauseKawa
    Homme Profil pro
    Technicien Help Desk, maintenance, réseau, système et +
    Inscrit en
    Juin 2006
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Technicien Help Desk, maintenance, réseau, système et +
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 725
    Par défaut break et list comprehension ?
    Bonjour,

    Question purement théorique.
    Auriez vous une idée pour utiliser un break sur une condition if dans une list compréhension ?
    Un exemple
    Soit le liste l
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    l = [0, 1, 0, 1, 1, 0, 1, 1, 1, 1]
    Et le code suivant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    for e in l:
        if e == 0:
            l.remove(e)
    Qui est traduisible comme ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    [l.remove(e) for e in l if e==0]
    (Je note bien la modification de la liste lors de son itération. .remove(item) supprimant le premier élément trouvé pas de problème ici)
    Comment traduire (est ce possible ?) ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    for e in l:
        if e == 0:
            l.remove(e)
        if 0 not in l:
            break
    (Soit en gros
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    while 0 in l: l.remove(0)
    mais avec une list compréhension)

    Merci

    @+

  2. #2
    Membre éprouvé
    Avatar de Luke spywoker
    Homme Profil pro
    Etudiant informatique autodidacte
    Inscrit en
    Juin 2010
    Messages
    1 077
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Etudiant informatique autodidacte

    Informations forums :
    Inscription : Juin 2010
    Messages : 1 077
    Par défaut
    Une liste de compréhension renvoie une liste qui subit un traitement d'après les structures conditionnelles quelle contient donc il faut lui affecter une variable qui contiendra le résultat du traitement de la liste de compréhension:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    >>>l = [0, 1, 0, 1, 1, 0, 1, 1, 1, 1]
    >>>while 0 in l :
           a=[l.remove(e) for e in l if e == 0] 
           if not a.__contains__(0) :
             break 
    >>>l
    >>>[1, 1, 1, 1, 1, 1, 1]
    Je sais pas si c'est ca que tu voulais faire.

  3. #3
    Membre Expert

    Homme Profil pro
    Diverses et multiples
    Inscrit en
    Mai 2008
    Messages
    662
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Diverses et multiples

    Informations forums :
    Inscription : Mai 2008
    Messages : 662
    Par défaut
    A mon humble avis, c’est tout simplement impossible… La syntaxe des comrehensions, pour puissante qu’elle soit, a tout de même ses limites.

    Et puis, j’ai quand même l’impression que tu en abuses déjà pas mal, là, non*?

    Quand je vois*:

    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    [l.remove(e) for e in l if e==0]

    …honnêtement, je frémis*!

    Certes, ça marche et fait (à peu près, essaye avec plusieurs 0 de suite pour voir) ce que tu veux, mais ce n’est pas ce pour quoi ont été conçues les comprehensions, il me semble bien plus sage ici d’en rester aux boucles classiques*! Après, si tu veux t’amuser, évidemment…

  4. #4
    Membre Expert
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2007
    Messages : 941
    Par défaut
    Je suis tout à fait d'accord avec mont29; une list comprehension est une expression et il vaut mieux la traiter comme tel.
    Par exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    l = [e for e in l if e != 0]
    Bien sûr ça ne fait pas la même chose que ton code, la liste n'est pas modifiée en place, et s'il existait d'autres références à la liste d'origine, celles-ci pointeront toujours sur l'ancienne liste qui n'est pas modifiée. Mais au niveau des performances, ce sera sans doute plus efficace, car remove peut être assez couteux vu qu'il doit faire une recherche et décaler tous les éléments qui suivent vers la gauche...

    [Edit]: suppression grosses bêtises.

    C'est généralement une mauvaise idée de modifier un container sur lequel on est en train d'itérer. Comme le dit mont29, si tu as deux 0 de suite dans la liste, le second ne sera pas supprimé, car remove va supprimer le premier, ce qui décalera tout le reste de la liste d'une position vers la gauche, et l'itération suivante sautera au-dessus de l'élement qui suit celui qui vient d'être supprimé. L'itérateur de liste ne fait pas une copie de la liste à son initialisation.

    Il y a un tas de solutions possibles, par exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
    # solution 1
    for i in range(l.count(0)):
        l.remove(0)
     
    # solution 2
    try:
        while 1:
            l.remove(0)
    except ValueError:
        pass
     
    # solution 3
    i = 0
    while i < len(l):
        if l[i] == 0:
            del l[i]    # plus efficace que remove si on connait l'indice
        else:
            i = i+1    # on n'incrémente i que si on n'a rien supprimé

  5. #5
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 738
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 738
    Par défaut
    Salut,

    Je n'ai pas compris ce que voulait faire PauseKawa et comme l'exemple proposé ne me motive pas pour passer par une list compréhension...
    Je ne sais pas.

    Pour l'instant, j'ai compris: "on veut modifier la liste" in place pour éviter que les variables pointant vers cette liste loupent sa modification.

    Lorsqu'on écrit:
    L = [0, 1, 0, 1]
    "L" est une variable dans l'espace de nom courant à laquelle on a assigné la liste [0, 1, 0, 1]. La liste est une boîte de type "container". Autrement dit boîte et contenu sont "différents" - avec un entier boite et contenu sont "identiques".
    L est une variable qui pointe sur la "boîte".

    Pratiquement, il est possible de faire:
    L = [e for e in L if e != 0], ou
    L[:] = [e for e in L if e != 0]
    et çà ne fait pas la même chose.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    >>> L = [0, 1, 0, 1] # initialisation de L a l'adresse d'une liste contenant...
    >>> R = L  # R pointe vers la même chose que L
    >>> R # contrôle:
    [0, 1, 0, 1]
    >>> L[:] = [ x for x in L if x != 0 ] # on remplace le contenu de la liste
    >>> R # la référence "suit"...
    [1, 1]
    >>> L = [0, 1, 0, 1] # on colle a L une autre boîte...
    >>> R # dans ce cas, le contenu de a reste inchangé.
    [1, 1]
    >>>
    Hmm. Pour l'instant, pas besoin de passer par .remove pour changer l'ensemble du contenu de la liste.
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  6. #6
    Membre Expert
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2007
    Messages : 941
    Par défaut
    Bien vu wiztricks,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    L[:] = [ x for x in L if x != 0 ]
    Ce n'est pas tout à fait une modification "en place", mais l'effet est le même, et c'est plus simple et plus efficace.

    Je n'avais pas remarqué que le PO était PauseKawa; j'aurais répondu un peu différemment si je l'avais remarqué...

    L'exemple est mal choisi, mais la question est intéressante à un niveau plus général. Je dirais que non, il n'est pas possible de "sortir d'une list comprehension avant la fin", mais on peut inventer des trucs un peu tordus:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    def break_iterator(iterable, cond):
            for e in iter(iterable):
                if cond(e): break
                yield e
     
    # reproduit l'exemple original (avec la même erreur)
    l = [0, 1, 0, 1, 1, 0, 1, 1, 1, 1]
     
    [l.remove(e) for e in break_iterator(l, lambda _: 0 not in l) if e == 0]
     
    print l
    [EDIT:] En fait, il existe un générateur similaire dans la librairie standard: itertools.takewhile.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    from itertools import takewhile
     
    # reproduit l'exemple original avec la même erreur
    l = [0, 1, 0, 1, 1, 0, 1, 1, 1, 1]
     
    [l.remove(e) for e in takewhile(lambda _: 0 in l, l) if e == 0]
     
    print l

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Iterator over lists comprehensions ?
    Par ®om dans le forum Général Python
    Réponses: 3
    Dernier message: 27/09/2011, 23h47
  2. List comprehension ou boucle for?
    Par Gui13 dans le forum Général Python
    Réponses: 10
    Dernier message: 07/06/2010, 08h52
  3. probleme de comprehension des listes
    Par marsafari dans le forum Général Python
    Réponses: 2
    Dernier message: 29/07/2009, 15h37
  4. requête insert et comprehension list
    Par polo42 dans le forum Général Python
    Réponses: 5
    Dernier message: 17/05/2008, 10h48
  5. Copier un dictionnaire par une list comprehension
    Par Sve@r dans le forum Général Python
    Réponses: 6
    Dernier message: 12/05/2008, 10h25

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo