Python:在迭代时向列表中添加元素

Python:在迭代时向列表中添加元素,python,iteration,Python,Iteration,我知道不允许在迭代列表时删除元素,但允许在迭代时向python列表添加元素。以下是一个例子: for a in myarr: if somecond(a): myarr.append(newObj()) 我在我的代码中尝试过这个,它似乎工作得很好,但是我不知道这是否是因为我很幸运,它在将来的某个时候会崩溃 编辑:我不想复制这个列表,因为“myarr”很大,所以速度太慢。我还需要用“somecond()”检查附加的对象 编辑:在某一点上,“somecond

我知道不允许在迭代列表时删除元素,但允许在迭代时向python列表添加元素。以下是一个例子:

    for a in myarr:
      if somecond(a):
          myarr.append(newObj())
我在我的代码中尝试过这个,它似乎工作得很好,但是我不知道这是否是因为我很幸运,它在将来的某个时候会崩溃

编辑:我不想复制这个列表,因为“myarr”很大,所以速度太慢。我还需要用“somecond()”检查附加的对象

编辑:在某一点上,“somecond(a)”将为false,因此不可能存在无限循环


编辑:有人问起“somecond()”函数。myarr中的每个对象都有一个大小,并且每次“somecond(a)”为true并且将新对象追加到列表中时,新对象的大小都将小于a。“somecond()”有一个epsilon来表示对象有多小,如果对象太小,它将返回“false”

复制原始列表,对其进行迭代, 请参阅下面修改的代码

for a in myarr[:]:
      if somecond(a):
          myarr.append(newObj())
那么根据

修改序列是不安全的 在循环中迭代(此 只能对可变序列发生 类型(例如列表)。如果你需要 修改正在迭代的列表 (例如,要复制选定对象 项目)您必须在副本上迭代


通过i直接访问列表元素。然后,您可以将以下内容附加到列表中:

for i in xrange(len(myarr)):
    if somecond(a[i]):
        myarr.append(newObj())
你可以这样做

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

您可以使用itertools中的
islice
,在列表的较小部分上创建迭代器。然后,您可以将条目附加到列表中,而不会影响正在迭代的项目:

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

更好的是,您甚至不必迭代所有元素。您可以增加步长。

扩展S.Lott的答案,以便同时处理新项目:

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

最后一个列表是在
done

中,为什么不用惯用的C语言编写呢?这应该是防弹的,但不会很快。我很确定在Python中索引到一个列表会遍历链表,所以这是一个“Shlemiel-the-Painter”算法。但我倾向于不担心优化,直到明确某段代码确实是个问题。首先,让它发挥作用;如果有必要的话,那就考虑加快速度

如果要迭代所有元素,请执行以下操作:

i = 0  
while i < len(some_list):  
  more_elements = do_something_with(some_list[i])  
  some_list.extend(more_elements)  
  i += 1  
i=0
而我
如果只想迭代列表中最初的元素:

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
length = len(l)
for index in range(length):
    if somecond(l[index]):
        l.append(Obj())
i=0
原始长度=长度(一些列表)
而我<原版_len:
更多元素=使用(一些列表[i])做某事
一些\u列表。扩展(更多\u元素)
i+=1

我今天遇到了类似的问题。我有一个需要检查的项目清单;如果对象通过检查,则会将其添加到结果列表中。如果他们没有通过,我会对他们做一些更改,如果他们仍然可以工作(更改后大小>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个项目),这也很有效。

如果希望循环同时循环添加到列表中的元素,可以使用索引和while循环而不是for循环:

i = 0
while i < len(myarr):
    a = myarr[i];
    i = i + 1;
    if somecond(a):
        myarr.append(newObj())
i=0
而我
替代解决方案:

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

简而言之:如果您完全确定所有新对象都失败了
somecond()
检查,那么您的代码工作正常,只是浪费了一些时间来迭代新添加的对象

在给出正确答案之前,您必须理解为什么在迭代时更改list/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进行控制:

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
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)

问题是列表太大了,所以每次复制都会非常慢。@WesDec:请在声明它“非常慢”之前测量一下。这是一个肤浅的副本。这很快。@s.Lott:这个列表很容易超过1亿个元素,上面的循环重复了很多次。即使是浅拷贝也会很慢。@Justin Peel-您使用此解决方案的速度更快。如果您希望在附加项上使用相同的循环代码,同时保持其干燥,则可以使用此解决方案。似乎没有任何其他解决方案反对这种用例。复制列表不需要太多时间。这是一个浅拷贝,不是一个深拷贝。@s.Lott:这个列表很容易超过1亿个元素,上面的循环重复了很多次。即使是浅表副本也会很慢。既然你说你已经这样做了,那么你的循环是否会在列表中的附加项和原始项之间进行迭代?@WesDec:you appe