我想知道是否有一条快捷方式可以在 Python 列表中列出一个简单的列表。
我可以在 for 循环中做到这一点,但也许有一些很酷的 “单行”?我用reduce尝试了,但是我收到了一个错误。
码
l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
reduce(lambda x, y: x.extend(y), l)
错误信息
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <lambda>
AttributeError: 'NoneType' object has no attribute 'extend'
flat_list = [item for sublist in l for item in sublist]
意思是:
for sublist in l:
for item in sublist:
flat_list.append(item)
比目前发布的快捷方式快。 ( l
是要压扁的列表。)
这是一个相应的功能:
flatten = lambda l: [item for sublist in l for item in sublist]
为了证据,您可以像往常一样使用标准库中的timeit
模块:
$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' '[item for sublist in l for item in sublist]'
10000 loops, best of 3: 143 usec per loop
$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'sum(l, [])'
1000 loops, best of 3: 969 usec per loop
$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'reduce(lambda x,y: x+y,l)'
1000 loops, best of 3: 1.1 msec per loop
说明:当存在 L 个子列表时,基于+
的快捷方式(包括sum
隐含的用法)必然为O(L**2)
- 因为中间结果列表持续变长,在每个步骤都有新的中间结果列表对象被分配,并且必须复制先前中间结果中的所有项目(以及最后添加的一些新项目)。所以(为了简单而没有实际的失去一般性)说你有每个项目的 L 个子列表:第一个 I 项目来回复制 L-1 次,第二个 I 项目 L-2 次,依此类推; 总复制数是 I 乘以 x 的总和,从 1 到 L 排除,即I * (L**2)/2
。
列表理解只生成一个列表一次,并将每个项目(从其原始居住地点到结果列表)复制一次。
你可以使用itertools.chain()
:
>>> import itertools
>>> list2d = [[1,2,3],[4,5,6], [7], [8,9]]
>>> merged = list(itertools.chain(*list2d))
或者,在 Python> = 2.6 上,使用itertools.chain.from_iterable()
,它不需要解压缩列表:
>>> import itertools
>>> list2d = [[1,2,3],[4,5,6], [7], [8,9]]
>>> merged = list(itertools.chain.from_iterable(list2d))
这种方法可以说比[item for sublist in l for item in sublist]
更具可读性[item for sublist in l for item in sublist]
并且看起来更快:
[me@home]$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99;import itertools' 'list(itertools.chain.from_iterable(l))'
10000 loops, best of 3: 24.2 usec per loop
[me@home]$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' '[item for sublist in l for item in sublist]'
10000 loops, best of 3: 45.2 usec per loop
[me@home]$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'sum(l, [])'
1000 loops, best of 3: 488 usec per loop
[me@home]$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'reduce(lambda x,y: x+y,l)'
1000 loops, best of 3: 522 usec per loop
[me@home]$ python --version
Python 2.7.3
作者请注意 :这是低效的。但很有趣,因为单子很棒。它不适合生产 Python 代码。
>>> sum(l, [])
[1, 2, 3, 4, 5, 6, 7, 8, 9]
这只是对第一个参数中传递的 iterable 元素进行求和,将第二个参数视为总和的初始值(如果没有给出,则使用0
代替,这种情况会给你一个错误)。
因为你是对嵌套列表求和,实际上得到[1,3]+[2,4]
作为sum([[1,3],[2,4]],[])
,它等于[1,3,2,4]
。
请注意,仅适用于列表列表。对于列表列表,您需要另一种解决方案。