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 :

Fonctionnement des listes imbriquées


Sujet :

Python

  1. #1
    Futur Membre du Club
    Homme Profil pro
    Inscrit en
    Décembre 2013
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2013
    Messages : 4
    Par défaut Fonctionnement des listes imbriquées
    Bonjour,

    Je débute en Python et j'ai une petite incompréhension sur le fonctionnement de listes imbriquées. J'utilise du python 2.7.

    J'ai essayé le code suivant qui fonctionne correctement:
    >>> main=[[3,4],[1,2,5],[],[0,3,4]]
    >>> for p1,p2 in enumerate(main):
    ... print "P1/P2: ", p1,p2
    ... for val in p2:
    ... print "Value: ",val
    ...
    P1/P2: 0 [3, 4]
    Value: 3
    Value: 4
    P1/P2: 1 [1, 2, 5]
    Value: 1
    Value: 2
    Value: 5
    P1/P2: 2 []
    P1/P2: 3 [0, 3, 4]
    Value: 0
    Value: 3
    Value: 4
    J'accède bien à tous les éléments de mes listes. Mais si j'essaye de vider ces listes, il en oublie en cours de route. Qu'est-ce que j'ai oublié ?

    >>> main=[[3,4],[1,2,5],[],[0,3,4]]
    >>> for p1,p2 in enumerate(main):
    ... print "P1/P2: ", p1,p2
    ... for val in p2:
    ... print "Value: ",val
    ... main[p1].remove(val)
    ... print main
    ...
    P1/P2: 0 [3, 4]
    Value: 3
    [[4], [1, 2, 5], [], [0, 3, 4]]
    P1/P2: 1 [1, 2, 5]
    Value: 1
    [[4], [2, 5], [], [0, 3, 4]]
    Value: 5
    [[4], [2], [], [0, 3, 4]]
    P1/P2: 2 []
    P1/P2: 3 [0, 3, 4]
    Value: 0
    [[4], [2], [], [3, 4]]
    Value: 4
    [[4], [2], [], [3]]
    >>>
    Merci d'avance.

  2. #2
    Invité
    Invité(e)
    Par défaut
    Bonjour,

    Le problème ne vient pas de l'imbrication des listes.
    Il ne faut jamais supprimer ou insérer un élément dans un tableau en cours de parcours. La boucle de parcours se base sur les indices, or en supprimant des éléments au fur et à mesure que tu parcours le tableau, tu altères les indices.

    exemple :
    Tu pars de ['a', 'b']. Tu as donc
    indice 0 : 'a',
    indice 1 : 'b'
    Si tu parcours ton tableau en suppriment les éléments au fur et à mesure, les indices vont être faussés. A la première itération (indice 0, valeur 'a'), l'élément est supprimé. Donc 'b' se retrouve à l'indice 0... qui vient d'être traité et ne le sera donc plus.

    Dans ton cas, par exemple [1,2,5], à la deuxième itération (qui traite donc l'indice 1), 2 est passée à l'indice 0 et 5 à l'indice 1. Donc c'est 5 qui est traité au lieu de 2 qui à pris l'indice qui venait d'être traité.

    J'espère être clair.

  3. #3
    Futur Membre du Club
    Homme Profil pro
    Inscrit en
    Décembre 2013
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2013
    Messages : 4
    Par défaut
    Enerian,

    Merci, c'est assez clair. Je comprends que les indices soient modifiés.
    Mais comme j'utilise la fonction remove() qui utilise la valeur et non l'indice, ça me semble assez curieux qu'il ne s'y retrouve pas.

    Merci quand même.

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 20
    Par défaut
    Pourquoi ne pas itérer une copie de la liste et travailler directement sur la liste ?

    Exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    copieIterable = list(main) #On fait une copie de la liste et non de sa simple référence.
     
    for p1, p2 in enumerate(copieIterable) :
        for value in p2 :
            main[p1].remove(p2) #On supprime les valeurs de la liste initiale.

  5. #5
    Membre Expert Avatar de plxpy
    Homme Profil pro
    Ingénieur géographe
    Inscrit en
    Janvier 2009
    Messages
    792
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur géographe
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Janvier 2009
    Messages : 792
    Par défaut
    Bonjour

    Citation Envoyé par luluunix
    Pourquoi ne pas itérer une copie de la liste et travailler directement sur la liste ?
    Parce que, même sur l'exemple fourni par le PO, ça ne fonctionne pas !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    >>> main=[[3,4],[1,2,5],[],[0,3,4]]
    >>> copieIterable = list(main)
    >>> 
    >>> for p1, p2 in enumerate(copieIterable) :
    ...     for value in p2 :
    ...             main[p1].remove(p2)
    ... 
    Traceback (most recent call last):
      File "<stdin>", line 3, in <module>
    ValueError: list.remove(x): x not in list
    C'est plutôt "main[p1].remove(value)" qui aurait eu une petite chance de fonctionner. Mais même pas, et pour les mêmes raisons que le code original ne fonctionne pas :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    >>> main = [[1,2,2]]
    >>> copieIterable = list(main)
    >>> for p1, p2 in enumerate(copieIterable) :
    ...     for value in p2 :
    ...             main[p1].remove(value)
    ... 
    >>> 
    >>> main
    [[2]]

    Citation Envoyé par Franck31300
    Mais comme j'utilise la fonction remove() qui utilise la valeur et non l'indice, ça me semble assez curieux qu'il ne s'y retrouve pas.
    Relis les explications claires de Enerlan et tu verras "qu'attaquer" la liste avec des remove en croyant ne pas mettre la bazar dans les indices est vain !

    La seule façon de vider une liste élément par élément, est de s'attaquer au dernier indice (plus grand) et de remonter la liste en sens inverse.

    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
    >>> main=[[3,4],[1,2,5],[],[0,3,4]]
    >>> for liste in main:
    ...     for i in range(len(liste)-1,-1,-1):
    ...             del liste[i]
    ... 
    >>> main
    [[], [], [], []]
    >>> 
    >>> main=[[3,4],[1,2,5],[],[0,3,4]]
    >>> for liste in main:
    ...     while liste:
    ...             del liste[-1]
    ... 
    >>> main
    [[], [], [], []]
    >>>
    Mais tout ça n'est pas très pythonique. Pour vider (j'ai bien dit vider, et pas (ré-)affecter une nouvelle liste vide), il faut plutôt s'y prendre comme ça

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    >>> main=[[3,4],[1,2,5],[],[0,3,4]]
    >>> 
    >>> for liste in main:
    ...     del liste[:]
    ... 
    >>> main
    [[], [], [], []]
    >>>

  6. #6
    Futur Membre du Club
    Homme Profil pro
    Inscrit en
    Décembre 2013
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2013
    Messages : 4
    Par défaut
    Citation Envoyé par luluunix Voir le message
    Pourquoi ne pas itérer une copie de la liste et travailler directement sur la liste ?
    Merci pour la suggestion mais le résultat est le même à priori:
    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
    20
    21
    22
    23
    24
    >>> main=[[3,4],[1,2,5],[],[0,3,4]]
    >>> copieIterable = list(main)
    >>> for p1, p2 in enumerate(copieIterable) :
    ...   print "P1/P2: ", p1,p2
    ...   for val in p2:
    ...     print "Value: ",val
    ...     main[p1].remove(val)
    ...     print main
    ... 
    P1/P2:  0 [3, 4]
    Value:  3
    [[4], [1, 2, 5], [], [0, 3, 4]]
    P1/P2:  1 [1, 2, 5]
    Value:  1
    [[4], [2, 5], [], [0, 3, 4]]
    Value:  5
    [[4], [2], [], [0, 3, 4]]
    P1/P2:  2 []
    P1/P2:  3 [0, 3, 4]
    Value:  0
    [[4], [2], [], [3, 4]]
    Value:  4
    [[4], [2], [], [3]]
    >>>

  7. #7
    Invité
    Invité(e)
    Par défaut
    Ton problème se trouve au niveau de la deuxième boucle, pas de la première. C'est dans la deuxième que tu supprime les éléments d'un tableau que tu parcours.
    En faisant copieIterable = list(main), tu copies main mais les tableaux imbriqués dans main sont des références et donc sont conservés dans copieIterable.
    Pour garder la solution de la copie, il faudrait plutôt faire
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    main=[[3,4],[1,2,5],[],[0,3,4]]
    for p1, p2 in enumerate(main) :
        print "P1/P2: ", p1,p2
        copie = list(p2)  
        for val in copie: # l'itération se fait sur la copie dont les indices ne sont pas touchés
            print "Value: ",val
            main[p1].remove(val) # la suppression se fait sur le tableau original
            print main

    Mais bon, ce code n'a d'intérêt que pour comprendre l'origine de ton erreur.
    Si le but est de vider toutes les listes, la solution de plxpy est bien plus élégantes et efficace.

  8. #8
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 062
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 062
    Par défaut
    La solution de plxpy, peut-être légèrement plus efficace à voir

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    >>> main=[[3,4],[1,2,5],[],[0,3,4]]
    >>> for liste in main:
    ...     liste[:] = []
    ... 
    >>> main
    [[], [], [], []]

  9. #9
    Futur Membre du Club
    Homme Profil pro
    Inscrit en
    Décembre 2013
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2013
    Messages : 4
    Par défaut
    Merci pour ces explications.
    Je comprends le problème des indices même si cela me semble pas très logique.

    La fonction "remove" prend la valeur en paramètre en non l'indice. A aucun moment je n'ai voulu utiliser les indices justement à cause de ce problème. Il est dommage que la fonction remove s'en serve.
    Ce qui veut dire que quelque part, python garde en mémoire l'indice que cette valeur avait dans la version précédente de la liste? Ca ne me semble pas correct.
    Au moment où j’exécute le remove, la liste n'a que les éléments qui m'intéresse. De plus dans le cas où la sous liste à 3 éléments, la boucle est initialisé avec 3 éléments, elle devrait faire 3 itérations. Hors elle n'en fait que 2. Donc la boucle sait que l'élément n'existe plus mais pas la fonction remove ?

    L'idée n'est pas de vider simplement la liste sinon effectivement j'aurais utilisé le "del". L'idée est d'avoir cette structure constituée par un programme et une autre partie du code prend un élément, le traite et le supprime de la liste.
    Comme je débute, je testais une suppression avec boucle où j'aurais appelé le traitement de chacun des éléments, mais ça ne marche pas à l'évidence.

  10. #10
    Membre Expert Avatar de plxpy
    Homme Profil pro
    Ingénieur géographe
    Inscrit en
    Janvier 2009
    Messages
    792
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur géographe
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Janvier 2009
    Messages : 792
    Par défaut
    Je comprends le problème des indices même si cela me semble pas très logique.
    si tu ne comprends pas les petits schémas en dessous (je mis ça en code pour garder les espacements, mais la coloration syntaxique ...), tu ne peux rien bâtir de solide par la suite

    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
    20
    départ
     
              +-----+-----+-----+-----+   
    L c'est   | 'a' | 'b' | 'c' | 'd' |  
              +-----+-----+-----+-----+   
                 0     1     2     3       <---- indices
     
    L.remove('b')
     
              +-----+-----+-----+
    L c'est   | 'a' | 'c' | 'd' |
              +-----+-----+-----+
                 0     1     2       <---- indices
     
    del L[1]
     
              +-----+-----+
    L c'est   | 'a' | 'd' |
              +-----+-----+
                 0     1       <---- indices

Discussions similaires

  1. Problème de style sur un menu avec des listes imbriquées
    Par tarentaise dans le forum Mise en page CSS
    Réponses: 1
    Dernier message: 04/08/2011, 13h23
  2. Question sur le fonctionnement des liste lié
    Par DeeVoiD dans le forum Ruby on Rails
    Réponses: 2
    Dernier message: 19/05/2009, 12h14
  3. [RegEx] Un bbcode maison - faire des listes imbriquées
    Par Fido166 dans le forum Langage
    Réponses: 2
    Dernier message: 19/09/2008, 13h19
  4. Présentation dans des listes imbriquées
    Par Ghusse dans le forum Balisage (X)HTML et validation W3C
    Réponses: 6
    Dernier message: 29/09/2005, 09h35

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