list - Making a flat list out of list of lists in Python

  显示原文与译文双语对照的内容

可能的重复项:
在 python 中平铺浅列表
对展平序列序列的理解

我想知道是否有一个快捷方式在 python 列表中列出一个简单列表。

我可以在a 循环,中进行,但可能有一些很酷的"one-liner"? 我试过用降低,但我得到了一个错误。

代码


l = [[1,2,3],[4,5,6], [7], [8,9]]
reduce(lambda x,y: x.extend(y),l)

英镑错误消息

回溯( 最近一次最近的通话): 文件"",第 1行,在文件"",第 1行,AttributeError: ''NoneType'对象没有属性'扩展''

时间:

[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的子列表--作为中间结果列表一直在越来越长,每个步骤中一个新的中间结果的列表对象获取通过( 还有一些新的添加到末尾) 分配,所有的物品在前面的中间结果需要被复制。 所以( 为了简单而没有实际的通用损失) 说你每个项目都有我的子列表: 我在 1来卸掉,换句话说,第一中排除项是来回复制 L-2 L-1次,第二个实例,项目时间等等;总份数是我次数之和x 为x 。

列表理解只生成一个列表,一次复制( 从原始居住地到结果列表) 上的每一项,同时也只复制一次。

你可以使用 itertools.chain():


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

或者,在 python> =2上,使用 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] 看起来也更快了:


[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

@Nadia: 你必须使用更长的列表。 然后你会看到差异相当惊人 ! len(l) = 1600的结果


A took 14.323 ms
B took 13.437 ms
C took 1.135 ms

在哪里:


A = reduce(lambda x,y: x+y,l)
B = sum(l, [])
C = [item for sublist in l for item in sublist]


>>> l = [[1,2,3],[4,5,6], [7], [8,9]]
>>> reduce(lambda x,y: x+y,l)
[1, 2, 3, 4, 5, 6, 7, 8, 9]

示例中的extend() 方法修改 x 而不是返回有用的值( 哪个 reduce() 需要) 。

执行 reduce 版本的更快速的方法是


>>> import operator
>>> l = [[1,2,3],[4,5,6], [7], [8,9]]
>>> reduce(operator.add, l)
[1, 2, 3, 4, 5, 6, 7, 8, 9]

我把我的语句收回。 sum不是赢家。 虽然列表较小,但速度更快。 但是随着更大的列表,性能会显著下降。


>>> timeit.Timer(
 '[item for sublist in l for item in sublist]',
 'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]] * 10000'
 ).timeit(100)
2.0440959930419922

总和版本仍运行了超过一分钟,但还没有完成处理 !

对于中等列表:


>>> timeit.Timer(
 '[item for sublist in l for item in sublist]',
 'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]] * 10'
 ).timeit()
20.126545906066895
>>> timeit.Timer(
 'reduce(lambda x,y: x+y,l)',
 'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]] * 10'
 ).timeit()
22.242258071899414
>>> timeit.Timer(
 'sum(l, [])',
 'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]] * 10'
 ).timeit()
16.449732065200806

使用小列表和时间: number=1000000


>>> timeit.Timer(
 '[item for sublist in l for item in sublist]',
 'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]]'
 ).timeit()
2.4598159790039062
>>> timeit.Timer(
 'reduce(lambda x,y: x+y,l)',
 'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]]'
 ).timeit()
1.5289170742034912
>>> timeit.Timer(
 'sum(l, [])',
 'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]]'
 ).timeit()
1.0598428249359131

你的函数不起作用的原因: 扩展扩展数组 in-place,但不返回它。 你仍然可以从lambda返回x,使用一些技巧:


reduce(lambda x,y: x.extend(y) or x, l)

注意:扩展在列表中比+ 高效。

...