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

11 views

©2020 by EasyCSTech. Special thanks to IPinfo​ and EasyNote.