2016-07-30 2 views
0

В моей программе я имею много линии, где мне нужно как перебрать что-то и изменить его в том же for цикле.питона - как одновременно перебирать и изменять список, набор, и т.д.

Однако, я знаю, что изменение вещи, над которой вы итерацией плохо потому, что он может - вероятно будет - привести к нежелательному результату.

Так что я делал что-то вроде этого:

for el_idx, el in enumerate(theList): 
    if theList[el_idx].IsSomething() is True: 
     theList[el_idx].SetIt(False) 

Это лучший способ сделать это?

+0

Вы фактически не изменяете список в этом коде. 'theList [idx] .SetIt (False)' может изменить элемент списка, но он не коснется списка. Здесь вам не нужно перебирать индексы. – user2357112

+0

Тем не менее, когда вы думаете, что вам нужно что-то изменить, итерации по нему, лучший способ действий - это, как правило, изменить ситуацию, поэтому вам не нужно это делать. Часто это путем вычисления модифицированной версии списка/set/whatever и последующей замены оригинала на новую версию. – user2357112

+0

@ user2357112 да, это простой способ, но как насчет памяти? В моей текущей работе это не проблема, но как бы вы это сделали, если это была проблема? – Adrian

ответ

1

Это концептуальное недоразумение.

Опасность для изменения самого списка изнутри итерации из-за того, что Python переводит цикл в код нижнего уровня. Это может привести к неожиданным побочным эффектам во время итерации, есть хороший пример здесь:

https://unspecified.wordpress.com/2009/02/12/thou-shalt-not-modify-a-list-during-iteration/

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

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

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

+0

Да, это мой прецедент - изменение элементов, но не добавление или удаление элементов. – Adrian

+0

Но в том случае, когда я делаю оба - добавление/удаление + изменение - есть ли лучший/более чистый способ сделать это, чем с индексами? – Adrian

+0

Сложно сказать, не видя, почему вы хотите это сделать. Вы можете отложить добавление/удаление до итерации. Вы можете выскочить из списка, пока он не будет исчерпан, и создать новый список по ходу (возможно, в функции генератора), как если бы это была очередь. Вы можете просто использовать индексы. Вы можете создать пользовательскую оболочку вокруг списка, который соответствует вашим требованиям. – James

-1

вы могли бы получить индекс первого

idx = [ el_idx for el_idx, el in enumerate(theList) if el.IsSomething() ] 
[ theList[i].SetIt(False) for i in idx ] 
+0

Я не понимаю, что это делает. Я понимаю понимание списка, но не двойное понимание. – Adrian

+0

@Adrian первая строка получает индекс, который el.IsSomehing() является True. вторая строка - заданное значение для этих элементов на основе результата первой строки – galaxyan

0

Ваша проблема, как представляется, для меня неясным. Но если мы говорим о вредоносном изменении списка во время итерации цикла for в Python. Я могу думать о двух сценариях.

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

например. Вы хотите написать программу с такими входами и выходами, как эти.

Вход:

[1, 2, 3, 4] 

Ожидаемый результат:

[1, 3, 6, 10] #[1, 1 + 2, 1 + 2 + 3, 1 + 2 + 3 + 4] 

Но ...Вы пишете код таким образом:

#!/usr/bin/env python 

mylist = [1, 2, 3, 4] 

for idx, n in enumerate(mylist): 
    mylist[idx] = sum(mylist[:idx + 1]) 
print mylist 

Результат:

[1, 3, 7, 15] # undesired result 

Второй, вы внести некоторые изменения на размер списка во время итерации for цикла.

например. От python-delete-all-entries-of-a-value-in-list:

>>> s=[1,4,1,4,1,4,1,1,0,1] 
>>> for i in s: 
... if i ==1: s.remove(i) 
... 
>>> s 
[4, 4, 4, 0, 1] 

Пример показывает нежелательный результат, который повышен с побочным эффектом изменения размера в списке. Это, очевидно, показывает вам, что каждый цикл в Python не может обрабатывать список с динамическим размером соответствующим образом. Ниже я покажу вам некоторые простой способ преодолеть эту проблему:

#!/usr/bin/env python 

    s=[1, 4, 1, 4, 1, 4, 1, 1, 0, 1] 
    list_size=len(s) 
    i=0 

    while i!=list_size: 
     if s[i]==1: 
      del s[i] 
      list_size=len(s) 
     else: 
      i=i + 1 

    print s 

Результат:

[4, 4, 4, 0] 

Заключение: Это, безусловно, не вреден для изменения каких-либо элементов в списке во время итерации цикла, если вы не 1) внести изменения в размер списка 2) сделать некоторый побочный эффект вычислений по своему усмотрению.

Смежные вопросы