Подтвердить что ты не робот

Python: добавление элемента в список при повторении

Я знаю, что не разрешено удалять элементы во время итерации списка, но разрешено ли добавлять элементы в список python во время итерации. Вот пример:

    for a in myarr:
      if somecond(a):
          myarr.append(newObj())

Я пробовал это в своем коде, и, похоже, он работает нормально, но я не знаю, потому что мне просто повезло и что он сломается в какой-то момент в будущем?

EDIT: Я предпочитаю не копировать список, так как "myarr" огромен, и поэтому он будет слишком медленным. Также мне нужно проверить присоединенные объекты с помощью "somecond()".

EDIT: В какой-то момент "somecond (a)" будет ложным, поэтому не может быть бесконечного цикла.

EDIT: Кто-то спросил о функции "somecond()". Каждый объект в myarr имеет размер, и каждый раз, когда "somecond (a)" истинно, и новый список добавляется к списку, новый объект будет иметь размер меньше, чем a. "somecond()" имеет epsilon для того, как маленькие объекты могут быть, и если они слишком малы, он вернет "ложный",

4b9b3361

Ответ 1

Вы можете использовать islice из itertools для создания итератора по меньшей части списка. Затем вы можете добавлять записи в список, не влияя на элементы, которые вы повторяете:

islice( myarr, 0, len(myarr)-1 )

Даже лучше, вам даже не нужно перебирать все элементы. Вы можете увеличить размер шага.

Ответ 2

Почему бы вам просто не сделать это идиоматическим способом? Это должно быть пуленепробиваемым, но оно не будет быстрым. Я уверен, что индексирование в список в Python идет по связанному списку, так что это алгоритм "Шлемиель-художник". Но я стараюсь не беспокоиться об оптимизации, пока не станет ясно, что конкретный раздел кода действительно является проблемой. Сначала заставьте его работать; а затем беспокоиться о том, чтобы сделать это быстро, если это необходимо.

Если вы хотите перебрать все элементы:

i = 0  
while i < len(some_list):  
  more_elements = do_something_with(some_list[i])  
  some_list.extend(more_elements)  
  i += 1  

Если вы хотите только перебирать элементы, которые изначально были в списке:

i = 0  
original_len = len(some_list)  
while i < original_len:  
  more_elements = do_something_with(some_list[i])  
  some_list.extend(more_elements)  
  i += 1

Ответ 3

хорошо, согласно http://docs.python.org/tutorial/controlflow.html

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

Ответ 4

Вы можете сделать это.

bonus_rows = []
for a in myarr:
  if somecond(a):
      bonus_rows.append(newObj())
myarr.extend( bonus_rows )

Ответ 5

Короче. Если вы абсолютно уверены, что все новые объекты не пройдут проверку somecond(), тогда ваш код будет работать нормально, он просто тратит время на повторное использование вновь добавленных объектов.

Прежде чем дать правильный ответ, вы должны понять, почему он считает плохую идею изменять список /dict во время итерации. При использовании оператора for Python пытается быть умным и каждый раз возвращает динамически вычисляемый элемент. Возьмите list в качестве примера, Python запоминает индекс и каждый раз, когда он возвращает l[index] вам. Если вы меняете l, результат l[index] может быть беспорядочным.

ПРИМЕЧАНИЕ. Вот этот вопрос о стеке_поверхности, чтобы продемонстрировать это.

В худшем случае для добавления элемента при итерации бесконечный цикл, попробуйте (или нет, если вы можете прочитать ошибку) следующее в python REPL:

import random

l = [0]
for item in l:
    l.append(random.randint(1, 1000))
    print item

Он будет печатать номера без остановок до тех пор, пока память не будет исчерпана или не будет убита системой/пользователем.

Понимайте внутреннюю причину, обсудите решения. Вот несколько:

1. сделать копию списка происхождения

Итерирование списка координат и изменение скопированного.

result = l[:]
for item in l:
    if somecond(item):
        result.append(Obj())

2. когда контур заканчивается

Вместо управления управлением python вы решаете, как перебирать список:

length = len(l)
for index in range(length):
    if somecond(l[index]):
        l.append(Obj())

Перед повторением, вычислите длину списка и только цикл length раз.

3. хранить добавленные объекты в новом списке

Вместо того, чтобы изменять список происхождения, сохраните новый объект в новом списке и соедините его позже.

added = [Obj() for item in l if somecond(item)]
l.extend(added)

Ответ 6

сделать копию исходного списка, перебрать его, см. измененный код ниже

for a in myarr[:]:
      if somecond(a):
          myarr.append(newObj())

Ответ 7

Доступ к элементам списка непосредственно через i. Затем вы можете добавить в свой список:

for i in xrange(len(myarr)):
    if somecond(a[i]):
        myarr.append(newObj())

Ответ 8

У меня была аналогичная проблема сегодня. У меня был список предметов, требующих проверки; если объекты прошли проверку, они были добавлены в список результатов. Если они не пройдут, я немного изменил их и, если они все еще могут работать (размеp > 0 после изменения), я добавлю их в конец списка для повторной проверки.

Я пошел на решение вроде

items = [...what I want to check...]
result = []
while items:
    recheck_items = []
    for item in items:
        if check(item):
            result.append(item)
        else:
            item = change(item)  # Note that this always lowers the integer size(),
                                 # so no danger of an infinite loop
            if item.size() > 0:
                recheck_items.append(item)
    items = recheck_items  # Let the loop restart with these, if any

Мой список фактически представляет собой очередь, вероятно, должен был использовать какую-то очередь. Но мои списки небольшие (например, 10 элементов), и это тоже работает.

Ответ 9

Расширение ответа S.Lott так, чтобы обрабатывались и новые элементы:

todo = myarr
done = []
while todo:
    added = []
    for a in todo:
        if somecond(a):
            added.append(newObj())
    done.extend(todo)
    todo = added

Окончательный список находится в done.

Ответ 10

Вы можете использовать цикл while и while вместо цикла for, если вы хотите, чтобы цикл также перекрывал элементы, которые добавлены в список во время цикла:

i = 0
while i < len(myarr):
    a = myarr[i];
    i = i + 1;
    if somecond(a):
        myarr.append(newObj())

Ответ 11

Альтернативное решение в одной строке:

reduce(lambda x,y : x +[newObj] if somecond else x,myarr,myarr)