2
votes

Python ne modifie pas les valeurs lors de l'itération sur une liste avec zip (), mais le fait avec enumerate ()

Pourquoi Python fonctionne différemment lors d'une itération à l'aide de numéros d'index? Par exemple, avec la fonction zip (qui n'a pas d'index lorsqu'elle est utilisée dans la boucle for), une valeur n'est pas stockée dans une variable. Alors qu'avec la fonction enumerate () (qui me permet d'avoir un "index" dans la boucle foor), cela se passe normalement.

Une solution qui n'utilise pas index a des valeurs différentes pour ma variable "width" lorsque j'essaye de l'imprimer à l'intérieur et à l'extérieur de la boucle, ici la fonction zip () a été utilisée pour travailler avec les deux listes au en même temps sans avoir à gérer leurs index:

8
5
5
[8, 5, 5]

Le code ci-dessus produit la sortie non souhaitée suivante:

tableData = [['apples', 'oranges', 'cherries', 'banana'],
            ['Alice', 'Bob', 'Carol', 'David'],
            ['dogs', 'cats', 'moose', 'goose']]

def printTable(myListOfLists):
    colWidths = [0] * len(myListOfLists)
    for index, lists in enumerate(myListOfLists):
        for item in lists:
            if colWidths[index] < len(item):
                colWidths[index] = len(item)
        print(colWidths[index]) #This prints my 'width' rightly
    print(colWidths) #This ALSO prints my 'width' rightly

printTable(tableData)

Mais si j'utilise enumerate () (générant des index pour travailler avec les deux listes en même temps) les valeurs modifiées dans ma boucle for seront correctement enregistrées dans la variable width, voir l'exemple de code:

8
5
5
[0, 0, 0]

Cette deuxième sortie est:

tableData = [['apples', 'oranges', 'cherries', 'banana'],
            ['Alice', 'Bob', 'Carol', 'David'],
            ['dogs', 'cats', 'moose', 'goose']]

def printTable(myListOfLists):
    colWidths = [0] * len(myListOfLists)
    for lists, width in zip(myListOfLists, colWidths):
        for item in lists:
            if width < len(item):
                width = len(item)
        print(width) #This prints my 'width' rightly
    print(colWidths) #This prints my 'width' wrongly

printTable(tableData)

Alors, s'il vous plaît, comment puis-je travailler avec le zip () et avoir mon Variable "externe" modifiée? Qu'est-ce que je fais mal? Merci.


2 commentaires

En width = len (item) , vous réaffectez la variable (en changeant sa valeur d'une liste à une autre) width avec la valeur len (item) , vous ne travaillez pas avec la liste mais avec la variable elle-même. Dans le second scénario, colWidths est également une liste mais vous l'affectez en changeant l'élément sous un certain index.


S'il vous plaît, quelle est la bonne façon de le faire alors? @Damian


3 Réponses :


2
votes

Je crois que ce que vous voulez réaliser est d'obtenir la longueur de l'élément le plus long dans une sous-liste donnée à partir de tableData . Pour ce faire, vous pouvez obtenir la plus longue chaîne de la sous-liste, puis mesurer sa longueur comme ceci:

tableData = [['apples', 'oranges', 'cherries', 'banana'],
             ['Alice', 'Bob', 'Carol', 'David'],
             ['dogs', 'cats', 'moose', 'goose']]


def printTable(myListOfLists):
    colWidths = []
    for sub_list in myListOfLists:
        longest_item = max(sub_list, key=len)
        colWidths.append(len(longest_item))
    print(colWidths)


printTable(tableData)

modifier avec une explication:

En utilisant pour les listes, width in zip (myListOfLists, colWidths):

à chaque cycle que vous obtenez 1) liste unique avec des chaînes de tableData sous forme de listes . 2) entier, exactement 0 à partir de colWidths comme width

ensuite, lors de l'itération sur chaque texte comme 'pommes', 'oranges' etc.

ce que vous fais ici: width = len (item) c'est comme dire "maintenant width n'est plus 0, c'est len (item) , par ceci vous n'affectez pas la liste colWidths parce que vous ne travaillez pas avec, vous manipulez cette valeur 0 , elle n'est pas liée à la place dans la liste colWidths , c'est juste 0 qui est remplacé par len (item) sous le nom "width".


5 commentaires

J'ai essayé de laisser votre code autant que possible dans la forme originale, c'est pourquoi il existe différentes conventions de dénomination (une avec des traits de soulignement et une avec CamelCase)


Damian, merci mais j'essaye de: 1) comprendre pourquoi mon code ne fonctionne pas comme prévu. 2) comprendre comment cela peut fonctionner en utilisant le zip, le for et le if. Même si ce n'est pas la meilleure solution. Merci pour votre solution, mais elle ne répond toujours pas à ma question.


Oh, désolé alors. Je vais éditer le message avec une explication.


C'est à des fins d'apprentissage, comprenez-vous? J'ai besoin de comprendre pourquoi cela se comporte de cette manière. Alors je ne répéterai pas la même erreur. Désolé, mais si vous pouviez ajouter ces "détails" à votre réponse.


Aucun problème! C'est encore plus motivant pour moi d'expliquer! Ma réponse peut être un peu chaotique, mais j'espère que vous comprendrez.



1
votes

De cette façon, vous ne changerez pas la valeur de la liste dont vous avez besoin de l'index pour changer la valeur réelle.

example:

for i, (a, b) in enumerate(zip(alist, blist)):
    print i, a, b

un bon moyen de résoudre votre problème:

tableData = [['apples', 'oranges', 'cherries', 'banana'],
            ['Alice', 'Bob', 'Carol', 'David'],
            ['dogs', 'cats', 'moose', 'goose']]

def printTable(myListOfLists):
    colWidths = [0] * len(myListOfLists)
    for index, row in enumerate(myListOfLists):
        colWidths[index] = len(max(row, key=len))
    print(colWidths)

printTable(tableData)

ou

tableData = [['apples', 'oranges', 'cherries', 'banana'],
             ['Alice', 'Bob', 'Carol', 'David'],
             ['dogs', 'cats', 'moose', 'goose']]


data = [len(max(e, key=len)) for e in tableData]

print(data)

d'une autre main que vous pourriez essayer.

for e in [1, 2, 3]:
    e = 10  # this way is wrong 

data = [1, 2, 3]
for index, e in enumerate(data):
    e[index] = 50 # always it is needed an index  


1 commentaires

Merci, je pense que vous y avez pleinement répondu. Spécialement pour être si objectif et pour "for i, (a, b) in enumerate (zip (alist, blist))): print i, a, b"



2
votes

enumerate est une manière pythonique de générer des indices (similaire, mais plus idiomatique, for i in range (len (...):

alist = [1,2,3,4]
for i in alist:
   i = 5     # does nothing to alist

for i in range(4):
    alist[i] = 5    # changes an element of alist


0 commentaires