在循环中追加/扩展列表

1 投票
4 回答
11799 浏览
提问于 2025-04-17 02:02

我想在遍历一个列表的时候,给它添加新的元素:

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 个回答

1

如果你想要扩展列表,但只想遍历原来的列表,你可以遍历一个副本,而不是直接遍历原来的列表:

for item in a_list[:]:
     a_list.extend(fun(item))
2

使用 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)
2

你试过列表推导式吗?这个方法会在内存中创建一个单独的列表,然后在推导完成后把它赋值给你原来的列表。基本上,这和你的第二个例子是一样的,不过它是通过嵌套的列表推导式来实现的,而不是导入一个扁平化的函数。[编辑 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(我们在原始推导式中创建的所有列表)中取出来,并添加到一个新的列表中。

希望这样更清楚了。如果还有不明白的地方,我随时愿意进一步解释。

撰写回答