Enumerate() для нарезанного списка не работает должным образом

enumerate() для списка работает как положено.

def swap(nums, i, j):
    temp = nums[i]
    nums[i] = nums[j]
    nums[j] = temp

mylist = [0,1,22,33,4]

for pos, num in enumerate(mylist):
    print(pos,num)
    if pos == 0:
        swap(mylist,2,3)

В этом примере num показывает измененное значение, как и ожидалось.

0 0
1 1
2 33 <--
3 22 <-- 
4 4

Но если я изменю mylist на mylist[:-1], например:

def swap(nums, i, j):
    temp = nums[i]
    nums[i] = nums[j]
    nums[j] = temp

mylist = [0,1,22,33,4]

for pos, num in enumerate(mylist[:-1]):
    print(pos,num)
    if pos == 0:
        swap(mylist,2,3)

num не показывает измененное значение.

0 0
1 1
2 22 <--
3 33 <--

Почему это происходит?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
171
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Проблема не в функции enumerate.

На самом деле, делая mylist[:-1], вы создаете список новый и работаете над ним.

Поэтому, когда вы пытаетесь изменить свой список (swap(mylist,2,3)), вы изменяете исходный, а не новый (созданный mylist[:-1]).

Вы можете решить свою проблему, выполнив следующие действия:

new_list = mylist[:-1]
for pos, num in enumerate(new_list):
    print(pos,num)
    if pos == 0:
        swap(new_list,2,3)
Ответ принят как подходящий

Разница в том, что вы перечисляете копировать списка. В вашем первом примере вы перечисляете прямую ссылку на список, который вы изменяете, но во втором примере вы использовали нарезку в списке для перечисления. Нарезка возвращает новый объект списка.

Это важно, потому что вы изменяете то, на что ссылаются еще не повторенные позиции. Итерация списка использует постоянно увеличивающийся показатель для получения значений, изменение списка во время итерации может означать, что следующий индекс ссылается на другое значение.

То, что итерация выполняется с помощью функции enumerate(), на самом деле не имеет значения. У вас была бы та же проблема без enumerate():

for num in mylist:
    print(num)
    if num == 0:
        swap(mylist, 2, 3)

напечатал бы

0
1
33
22
4

и нарезка даст вам копию, поэтому:

for num in mylist[:-1]:
    print(num)
    if num == 0:
        swap(mylist, 2, 3)

выходы

0
1
22
33

Если цель состоит в том, чтобы пропустить последний элемент, то вместо создания копии путем нарезки вы можете использовать пронумерованную позицию для раннего выхода из цикла:

for pos, num in enumerate(mylist):
    if pos == len(mylist) - 1:
        break
    print(pos, num)
    if pos == 0:
        swap(mylist, 2, 3)

или вы можете использовать itertools.islice() функция

from itertools import islice

for pos, num in enumerate(islice(mylist, len(mylist) - 1)):
    print(pos, num)
    if pos == 0:
        swap(mylist, 2, 3)

или вы можете просто создать свою копию первый, а затем изменить индексы этой копии:

sliced = mylist[:-1]
for pos, num in enumerate(sliced):
    print(pos, num)
    if pos == 0:
        swap(sliced, 2, 3)

mylist[:-1] создает новый объект списка, но вы выполняете обмен, используя mylist.

Откуда вы знаете, что это другой объект?

Вы можете проверить это поведение, используя id():

>>> mylist = [0,1,22,33,4,5]
>>> id(mylist)
3954492760
>>> lst = mylist
>>> id(lst)
3954492760
>>> sliced = mylist[:-1]
>>> id(sliced)
3954492920

Если вы заметили, идентификатор sliced отличается.


Now coming to your code:
for pos, num in enumerate(mylist[:-1]):
    print(pos,num)
    if pos == 0:
        swap(mylist,2,3)
#              ^^^ - you used a different list object from what you were iterating over.

Исправление самый простой, которое вы можете сделать, это заранее нарезать:

sliced = mylist[:-1]
for pos, num in enumerate(sliced):
    print(pos,num)
    if pos == 0:
        swap(sliced,2,3)

Итак, как уже упоминалось, это не имеет ничего общего с enumerate.

Другие вопросы по теме