Python не изменяет значения во время перебора списка с помощью zip (), но делает это при использовании enumerate () - PullRequest
0 голосов
/ 28 января 2019

Почему Python работает по-разному при итерации с использованием индексов?Например, с помощью функции zip (которая не имеет индексов при использовании в цикле for) значение не сохраняется в переменной.В то время как с функцией enumerate () (которая позволяет мне иметь «индекс» в цикле foor) это происходит нормально.

Решение, которое не использует индекс, имеет разные значения для моей переменной "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)

Приведенный выше код выдает следующий нежелательный вывод:

8
5
5
[0, 0, 0]

Но если яиспользуйте enumerate () (создание индексов для одновременной работы с двумя списками), значения, измененные внутри цикла for, будут правильно сохранены в переменной ширины, см. пример кода:

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)

Эта втораявывод:

8
5
5
[8, 5, 5]

Тогда, пожалуйста, как я могу работать с zip () и изменить мою «внешнюю» переменную?Что я делаю неправильно?Спасибо.

Ответы [ 3 ]

0 голосов
/ 28 января 2019

таким образом, вы не будете изменять значение списка, вам нужен индекс, чтобы изменить реальное значение.

пример:

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  

хороший способ решить вашу проблему:

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)

или

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)

с другой стороны, вы можете попробоватьout.

for i, (a, b) in enumerate(zip(alist, blist)):
    print i, a, b
0 голосов
/ 28 января 2019

enumerate - это Pythonic способ генерирования индексов (похожий, но более идиоматический, 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)

Здесь lists и item взяты из myListOfLists, но вы явноизменение списка colWidths.

В первом случае вы изменяете переменную итерации, но не исходный список:

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

width - это переменная итерации. Но width = len(item) строка назначает новое значение переменной (name), разрывая ее связь с исходным массивом. На следующей итерации итератор снова устанавливает width. Список источников, colWidths не изменяется.

Этот шаблон верен для простых случаев:

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 голосов
/ 28 января 2019

Я полагаю, что вы хотите достичь, чтобы получить длину самого длинного элемента в данном подсписке от tableData.Для этого вы можете получить самую длинную строку из подсписка, а затем измерить ее длину следующим образом:

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)

изменить с объяснением:

Используя for lists, width in zip(myListOfLists, colWidths):

в каждом цикле вы получаете 1) один список со строками из tableData как lists.2) целое число, ровно 0 от colWidths как width

, затем при итерации по каждому тексту, например «яблоки», «апельсины» и т. Д.

что вы здесь делаете: width = len(item) все равно что сказать: «теперь ширина больше не равна 0, это len(item), этим вы не влияете на список colWidths, потому что вы не работаете с ним, вы манипулируете этим значением 0, этоне относится к месту в списке colWidths, это просто 0, который заменяется на len(item) под именем "width".

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...