简体   繁体   English

Python在使用zip()遍历列表时不会修改值,但是在使用enumerate()时会修改值

[英]Python don't modify values while iterating over a list with zip(), but does it while with enumerate()

Why Python works differently when iterating using index numbers? 为什么在使用索引号进行迭代时Python的工作方式有所不同? For example with the zip function (that don't has indexes when used in the for loop) a value isn't stored in a variable. 例如,对于zip函数(在for循环中使用时没有索引),值不会存储在变量中。 While with the enumerate() function (that allow me to have an "index" in the foor loop) it happens normally. 使用enumerate()函数(允许我在foor循环中使用“索引”)时,它通常会发生。

A solution that don't use index has different values for my "width" variable when I'm trying to print it inside and outside the loop, here the zip() function was used to work with the two lists at the same time without needing to deal with their indexes: 当我尝试在循环内部和外部打印索引时,不使用索引的解决方案的“ width”变量具有不同的值,这里的zip()函数用于同时处理两个列表,而没有需要处理其索引:

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)

The above code produces the following not desired output: 上面的代码产生以下不希望的输出:

8
5
5
[0, 0, 0]

But if I use enumerate() (generating indexes to work with the two lists at the same time) the values modified inside my for loop will be properly saved in the width variable, see the code example: 但是,如果我使用enumerate()(生成索引以同时使用两个列表),则在for循环中修改的值将正确保存在width变量中,请参见代码示例:

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)

This second output is: 第二个输出是:

8
5
5
[8, 5, 5]

Then, please, how can I work with the zip() and have my "external" variable modified? 然后,请如何使用zip()并修改“外部”变量? What am I doing wrong? 我究竟做错了什么? Thanks. 谢谢。

I believe, what you want to achieve is to get length of longest item in given sub-list from tableData . 我相信,您想要实现的是从tableData获得给定子列表中最长项目的长度。 To do that you can get longest string from sub-list and then measure its length like this: 为此,您可以从子列表中获取最长的字符串,然后像这样测量其长度:

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)

edit with explanation: 编辑说明:

By using for lists, width in zip(myListOfLists, colWidths): 通过使用for lists, width in zip(myListOfLists, colWidths):

on each cycle you're getting 1) single list with strings from tableData as lists . 在每个周期上,您将获得1)单个列表,其中tableData中的字符串作为lists 2) integer, exactly 0 from colWidths as width 2)整数,从colWidths作为width正好为0

then, on iteration over each text like 'apples', 'oranges' etc. 然后,在对每个文本(如“苹果”,“橙子”等)进行迭代时

what you're doing in here: width = len(item) is like saying "now width isn't 0 anymore, it's len(item) , by this you're not affecting list colWidths because you're not working with it, you're manipulating this 0 value, it's not related to place in colWidths list, it's just 0 which is replaced by len(item) under "width" name. 您在此处所做的操作: width = len(item)就像说“现在width不再是0,它是len(item) ,这样就不会影响列表colWidths因为您不使用它,您正在操纵此0值,它与colWidths列表中的位置colWidths ,而只是0,它由“ width”名称下的len(item)替换。

by this way you wont change the value of the list you need the index to change the real value. 这样,您就不会更改列表的值,而需要索引来更改实际值。

example: 例:

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  

a good way to solve your problem: 解决您的问题的好方法:

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)

or 要么

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)

on another hand you could try out. 另一方面,您可以尝试一下。

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

enumerate is a Pythonic way of generating indices (similar to, but more idiomatic, for i in range(len(...): enumerate是一种生成索引的Python方式(类似于,但for i in range(len(...):

colWidths = [0] * len(myListOfLists)
for index, lists in enumerate(myListOfLists):
    for item in lists:
        if colWidths[index] < len(item):
            colWidths[index] = len(item)

Here lists and item come from myListOfLists , but you explicitly modifying colWidths list. 这里的listsitem来自myListOfLists ,但是您显式修改了colWidths列表。

In the first case, you are modifying an iteration variable, but not the source list: 在第一种情况下,您要修改迭代变量,而不是源列表:

colWidths = [0] * len(myListOfLists)
for lists, width in zip(myListOfLists, colWidths):
    for item in lists:
        if width < len(item):
            width = len(item)

width is an iteration variable. width是一个迭代变量。 But the width = len(item) line assigns a new value to the variable (name), breaking its link with the source array. 但是width = len(item)行为变量(名称)分配了一个新值,从而中断了其与源数组的链接。 On the next iteration, width is again set by the iterator. 在下一次迭代中, width由迭代器再次设置。 The source list, colWidths does not change. 源列表colWidths不变。

This pattern is true for simple cases: 此模式适用于简单情况:

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

Changes to the iteration variable are tricky. 对迭代变量的更改非常棘手。 You have to understand when it represents something 'mutable', and not. 您必须了解它何时表示“可变”,而不是。 And understand the difference between assignment to a variable, and modifying an object (like a list). 并且了解分配给变量和修改对象(如列表)之间的区别。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM