如何将列表列表转换为平面列表?

2024-03-28 20:51:51 发布

您现在位置:Python中文网/ 问答频道 /正文

我想知道是否有一个快捷方式可以在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'

Tags: lambda代码in程序消息reduce列表for
3条回答

您可以使用^{}

>>> import itertools
>>> list2d = [[1,2,3], [4,5,6], [7], [8,9]]
>>> merged = list(itertools.chain(*list2d))

或者您可以使用^{},它不需要使用*运算符来解压缩列表:

>>> 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]更具可读性,而且似乎也更快:

$ python3 -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99;import itertools' 'list(itertools.chain.from_iterable(l))'
20000 loops, best of 5: 10.8 usec per loop
$ python3 -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 5: 21.7 usec per loop
$ python3 -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'sum(l, [])'
1000 loops, best of 5: 258 usec per loop
$ python3 -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99;from functools import reduce' 'reduce(lambda x,y: x+y,l)'
1000 loops, best of 5: 292 usec per loop
$ python3 --version
Python 3.7.5rc1

给定列表列表l

flat_list = [item for sublist in l for item in sublist]

也就是说:

flat_list = []
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

说明:基于+(包括sum中的隐含用法)的快捷方式是,O(L**2)当有L个子列表时——由于中间结果列表越来越长,在每个步骤中都会分配一个新的中间结果列表对象,并且必须复制上一个中间结果中的所有项(以及最后加了几个新的)。因此,为了简单起见,在不丧失一般性的情况下,假设每个I项都有L个子列表:第一个I项被来回复制L-1次,第二个I项被复制L-2次,依此类推;总的复制次数是I乘以x对x从1到L的总和,即I * (L**2)/2

列表理解只生成一个列表,一次,并将每个项目(从其原始居住地到结果列表)复制一次。

作者的注释:这是低效的。但是很有趣,因为monoids太棒了。它不适合生产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]

注意,这只适用于列表列表。对于列表列表,您需要另一个解决方案。

相关问题 更多 >