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