在循环中追加/扩展列表
我想在遍历一个列表的时候,给它添加新的元素:
for idx in xrange(len(a_list)):
item = a_list[idx]
a_list.extend(fun(item))
(fun是一个返回列表的函数。)
问题:
这样做已经是最好的方法了吗?还是有更简单、更紧凑的做法呢?
备注:
from matplotlib.cbook import flatten
a_list.extend(flatten(fun(item) for item in a_list))
这个方法应该可以用,但我不想让我的代码依赖于matplotlib。
for item in a_list:
a_list.extend(fun(item))
这个方法对我来说已经不错了,但似乎会导致无限循环。
背景:
我有很多节点(在一个字典里),其中一些节点是特殊的,因为它们在边界上。'a_list'包含这些特殊/边界节点的键。有时候会添加新的节点,然后每个新的边界节点都需要被添加到'a_list'里。新的边界节点可以通过旧的边界节点(这里用'fun'表示)来确定,而且每个边界节点可以添加多个新的节点。
4 个回答
如果你想要扩展列表,但只想遍历原来的列表,你可以遍历一个副本,而不是直接遍历原来的列表:
for item in a_list[:]:
a_list.extend(fun(item))
使用 itertools 库,可以这样写:
import itertools
a_list += itertools.chain(* itertools.imap(fun, a_list))
或者,如果你想让代码尽量简短:
a_list += sum(map(fun, a_list), [])
另外,你也可以直接写出来:
new_elements = map(fun, a_list) # itertools.imap in Python 2.x
for ne in new_elements:
a_list.extend(ne)
你试过列表推导式吗?这个方法会在内存中创建一个单独的列表,然后在推导完成后把它赋值给你原来的列表。基本上,这和你的第二个例子是一样的,不过它是通过嵌套的列表推导式来实现的,而不是导入一个扁平化的函数。[编辑 Matthias: 将 + 改为 +=]
a_list += [x for lst in [fun(item) for item in a_list] for x in lst]
编辑:来解释一下发生了什么。
首先,上面代码中间的这部分会先执行:
[fun(item) for item in a_list]
这段代码会对fun应用到a_list中的每一个item,并把结果添加到一个新的列表中。问题是,因为fun(item)返回的是一个列表,所以现在我们得到了一个列表的列表。接下来,我们会运行第二个(嵌套的)列表推导式,来遍历我们刚刚在原始推导式中创建的新列表里的所有列表:
for lst in [fun(item) for item in a_list]
这样我们就可以按顺序遍历所有的列表了。那么:
[x for lst in [fun(item) for item in a_list] for x in lst]
这意味着要把每个x(也就是每个项目)从每个lst(我们在原始推导式中创建的所有列表)中取出来,并添加到一个新的列表中。
希望这样更清楚了。如果还有不明白的地方,我随时愿意进一步解释。