при итерации через список, удаляющий объекты, не удалены некоторые объекты

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

list1 = [1, 2, 3, 4, 5, 6]
list2 = []

for item in list1:
    list2.append(item)
    list1.remove(item)

Но если я выполняю его, мой вывод похож на это:

>>> list1
[2, 4, 6]
>>> list2
[1, 3, 5]

Мой вопрос является трехкратным, я предполагаю: Почему это происходит, как я заставляю его работать, и я пропускаю невероятно простое решение как оператор 'перемещения' или что-то?

7
задан Kevin 15 October 2012 в 20:22
поделиться

10 ответов

Причина в том, что вы (добавляете и) удаляете из первого списка, в результате чего он становится меньше. Таким образом, итератор останавливается до того, как можно будет пройти по всему списку.

Чтобы добиться желаемого, сделайте следующее:

list1 = [1, 2, 3, 4, 5, 6]
list2 = []

# You couldn't just make 'list1_copy = list1',
# because this would just copy (share) the reference.
# (i.e. when you change list1_copy, list1 will also change)

# this will make a (new) copy of list1
# so you can happily iterate over it ( without anything getting lost :)
list1_copy = list1[:]

for item in list1_copy:
    list2.append(item)
    list1.remove(item)

list1 [start: end: step] - это синтаксис нарезки : когда вы покидаете start ] empty по умолчанию 0, когда вы оставляете end пустым, это максимально возможное значение. Итак, list1 [:] означает все в нем . (спасибо Wallacoloo)

Как говорили некоторые парни, вы также можете использовать метод extension объекта list , чтобы просто скопировать один список в другой, если это было ваше намерение. (Но я выбрал способ, указанный выше, потому что это близко к вашему подходу.)

Поскольку вы новичок в python, у меня есть кое-что для вас: Dive Into Python 3 - это бесплатно и легко. - Повеселись!

8
ответ дан 6 December 2019 в 06:23
поделиться

@potatocubed: Многие из приведенных ответов решают приведенный вами тривиальный пример ("переместить список1 в список2"), но не объясняют, "почему "более глубокой проблемы, которая заключается в изменении списка по мере его перебора. Изучите ответ С.Лотта ...

0
ответ дан 6 December 2019 в 06:23
поделиться

Использование списка:

list2 = [item for item in list1]

Свяжите имя list2 с тем же объектом, что и list1 :

list2 = list1

(Обратите внимание, что если вы измените содержимое list1 , list2 будут изменены соответственно.)

Создайте копию list1 и привяжите ее к имени list2 :

list2 = list1[:]

In в этом случае list1 и list2 - разные объекты.

1
ответ дан 6 December 2019 в 06:23
поделиться

Необходимый навык отладки: Добавьте print операторы. (или функции print в Python 3)

>>> list1= [1, 2, 3, 4, 5, 6]
>>> for item in list1:
...     print item
...     list1.remove(item)
...     print list1
... 
1
[2, 3, 4, 5, 6]
3
[2, 4, 5, 6]
5
[2, 4, 6]

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

Python выбирает элемент на позиции 0 из списка.

Затем вы удаляете элемент, изменяя список.

Затем Python выбирает элемент в позиции 1 из списка (похоже, пропуская элемент)

Вы удаляете этот элемент, изменяя список.

Затем Python выбирает элемент на позиции 2 из списка (кажется, что он пропускает элемент)

Вы удаляете этот элемент, изменяя список.

Затем Python хотел бы выбрать элемент в позиции 3, но такого элемента нет. Поэтому цикл останавливается.

4
ответ дан 6 December 2019 в 06:23
поделиться

Существует также скромная функция copy (или deepcopy, если у вас сложные объекты, а не просто целые числа в списке):

from copy import copy

list2 = copy(list1)

Вы можете получить более подходящий ответ, если объясните, чего вы пытаетесь достичь (если только вы не изучаете списки в python).

"Переменные" в Python - это просто имена/ссылки, поэтому деструктивное копирование, которое вы, похоже, хотите сделать, выглядит несколько странно. Если вы хотите, чтобы список2 имел те же значения, что и список1, вы можете просто сделать:

list2 = list1 # now they are both referring to the same list

А если после этого вы захотите использовать список1 для чего-то другого, вы можете просто сделать:

list1 = ['A', 'B', 'C']
1
ответ дан 6 December 2019 в 06:23
поделиться

Вы не должны изменять список во время итерации по нему. Это заставляет итератор указывать не на тот элемент. После обработки первого элемента итератор указывает на index = 1, но поскольку вы удалили элемент, следующий элемент теперь имеет нулевой индекс, поэтому он будет пропущен. Вот почему вы обрабатываете только все остальные предметы.

Попробуйте:

 list2.extend(list1) # This appends all items from list1 to list2.
 del list1[:] # From ChristopheD's post.
3
ответ дан 6 December 2019 в 06:23
поделиться

Точно так, как говорит ChristopheD.

Можно сделать следующее:

list1 = [1, 2, 3, 4, 5, 6]
list2 = []

for item in list1:
    list2.append(item)

list1 = []

Это очистит список1.

Редактировать Он / она обновил свой пост. Я оставлю это как небольшую альтернативу.

1
ответ дан 6 December 2019 в 06:23
поделиться

Вы удаляете элементы из списка 1 во время итерации Это.

Это напрашивается на неприятности.

Попробуйте следующее:

>>> list1 = [1,2,3,4,5,6]
>>> list2 = []
>>> list2 = list1[:] # we copy every element from list1 using a slice
>>> del list1[:] # we delete every element from list1
8
ответ дан 6 December 2019 в 06:23
поделиться

Попробуйте вместо этого:

list1 = [1, 2, 3, 4, 5, 6]
list2 = []

list2.extend(list1)
list1[:] = []
1
ответ дан 6 December 2019 в 06:23
поделиться

Как видно из других ответов, вы пытаетесь изменить список во время итерации по нему. Это не работает. Существует много способов копирования одного списка в другой. Я провел несколько тестов, чтобы посмотреть, насколько быстрым является каждый подход:

>>> timeit.Timer('list2 = list1[:]', 'list1 = range(10**3)').timeit(10**6)
3.9134418964385986

>>> timeit.Timer('list2 = []; list2.extend(list1)', 'list1 = range(10**3)').timeit(10**6)
4.9082601070404053

>>> timeit.Timer('list2 = copy.copy(list1)', 'import copy; list1 = range(10**3)').timeit(10**6)
7.5023419857025146

>>> timeit.Timer('list2 = [i for i in list1]', 'list1 = range(10**3)').timeit(10**6)
95.697894811630249

Синтаксис slice является самым быстрым. Он намного быстрее, чем использование понимания списка.

Чтобы очистить список, можно использовать:

del list1[:]
1
ответ дан 6 December 2019 в 06:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: