在迭代时向列表添加元素
我知道在遍历一个列表的时候是不允许删除元素的,但在遍历时添加元素到 Python 列表中是否可以呢?下面是一个例子:
for a in myarr:
if somecond(a):
myarr.append(newObj())
我在代码中试过这个,似乎运行得很好,但我不知道这是不是因为我运气好,未来会不会出问题?
我不想复制这个列表,因为 myarr
非常大,这样会太慢。而且我需要用 somecond()
来检查添加的对象。
在某个时刻,somecond(a)
会返回假值,所以不会出现无限循环。
每个 myarr
中的对象都有大小,每次 somecond(a)
返回真时,如果往列表中添加一个新对象,这个新对象的大小会比 a
小。somecond()
有一个阈值,规定了对象可以有多小,如果对象太小,它会返回“假”。
12 个回答
28
根据 http://docs.python.org/tutorial/controlflow.html 的说法,
在循环中修改正在遍历的序列是不安全的(这只会发生在可变序列类型,比如列表)。如果你需要修改正在遍历的列表(比如,复制选定的项目),你必须遍历一个副本。
65
你为什么不直接用C语言的标准方式来做呢?这样做应该是非常稳妥的,但速度可能会慢。我记得在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
12
你可以使用 islice
这个工具,它来自 itertools,来创建一个只包含列表中一部分的迭代器。这样,你就可以在不影响你正在遍历的那些项目的情况下,往列表里添加新的内容:
islice(myarr, 0, len(myarr)-1)
更棒的是,你甚至不需要遍历所有的元素。你可以设置一个步长,逐步增加。