python如何打平一个嵌套列表
假设有一个列表,列表里面的元素也还是列表,那么如何将这个多层列表变成一层呢?当然可以写个for循环来完成:
>>> l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
>>> r = []
>>> for item in l:
... r.extend(item)
...
>>> r
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>
但是有没有更酷一点的方式可以一行代码完成呢?当然有,下面来看看第一种方法。
列表生成式:
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)
但是列表生成式更快,这里有个简单的性能评估:
$ 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操作每次都会生成一个新的中间列表,当列表很长了以后copy会很费空间也费时;而列表生成式每次都在生成列表上进行操做,所以更快。
itertools.chain():
import itertools
list2d = [[1,2,3], [4,5,6], [7], [8,9]]
merged = list(itertools.chain(*list2d))
或者可以使用itertools.chain.from_iterable(),这样就不需要在列表前打上*号(*号表示unpack列表):
import itertools
list2d = [[1,2,3], [4,5,6], [7], [8,9]]
merged = list(itertools.chain.from_iterable(list2d))
functools.reduce():
functools.reduce(operator.iconcat, a, [])
其他:
直接用numpy内置flat函数:
list(numpy.array(a).flat)
或者numpy内置concatenate函数:
list(numpy.concatenate(a))
还有将列表变成string进行操作的:
elements = [[180.0, 1, 2, 3], [173.8], [164.2], [156.5], [147.2], [138.2]]
list(map(float, str(elements).replace("[", "").replace("]", "").split(",")))
方法大概就这么多,下面来看下各个方法的性能:
import functools
import itertools
import numpy
import operator
import perfplot
def forfor(a):
return [item for sublist in a for item in sublist]
def sum_brackets(a):
return sum(a, [])
def functools_reduce(a):
return functools.reduce(operator.concat, a)
def functools_reduce_iconcat(a):
return functools.reduce(operator.iconcat, a, [])
def itertools_chain(a):
return list(itertools.chain.from_iterable(a))
def numpy_flat(a):
return list(numpy.array(a).flat)
def numpy_concatenate(a):
return list(numpy.concatenate(a))
perfplot.show(
setup=lambda n: [list(range(10))] * n,
kernels=[
forfor, sum_brackets, functools_reduce, functools_reduce_iconcat,
itertools_chain, numpy_flat, numpy_concatenate
],
n_range=[2**k for k in range(16)],
xlabel='num lists'
)
性能图示如下:

随着列表长度增加,sum_brackets方法性能下降很快。
参考链接:https://stackoverflow.com/questions/952914/how-to-make-a-flat-list-out-of-list-of-lists
48 views0 comments