关于python:如何在不使用numpy的情况下将2d列表展平为1d?

how to flatten a 2D list to 1D without using numpy?

本问题已经有最佳答案,请猛点这里访问。

我有一个列表如下:

1
[[1,2,3],[1,2],[1,4,5,6,7]]

我想把它压扁成[1,2,3,1,2,1,4,5,6,7]

在不使用numpy的情况下,是否有一个轻量级函数来执行此操作?


不使用numpy(ndarray.flatten可以使用chain.from_iterable这是itertools.chain的备用构造函数:

1
2
>>> list(chain.from_iterable([[1,2,3],[1,2],[1,4,5,6,7]]))
[1, 2, 3, 1, 2, 1, 4, 5, 6, 7]

也可以在python 2中使用reduce,在3中使用functools.reduce,这对短列表更有效(不要在长列表中使用):

1
2
3
4
In [4]: from functools import reduce # Python3

In [5]: reduce(lambda x,y :x+y ,[[1,2,3],[1,2],[1,4,5,6,7]])
Out[5]: [1, 2, 3, 1, 2, 1, 4, 5, 6, 7]

或者用operator.add代替lambda,速度稍微快一点:

1
2
3
4
5
6
7
8
9
10
In [6]: from operator import add

In [7]: reduce(add ,[[1,2,3],[1,2],[1,4,5,6,7]])
Out[7]: [1, 2, 3, 1, 2, 1, 4, 5, 6, 7]

In [8]: %timeit reduce(lambda x,y :x+y ,[[1,2,3],[1,2],[1,4,5,6,7]])
789 ns ± 7.3 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [9]: %timeit reduce(add ,[[1,2,3],[1,2],[1,4,5,6,7]])
635 ns ± 4.38 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

或者作为另一种方法,你可以使用列表理解:

1
[j for sub in [[1,2,3],[1,2],[1,4,5,6,7]] for j in sub]

基准:

1
2
3
4
5
6
:~$ python -m timeit"from itertools import chain;chain.from_iterable([[1,2,3],[1,2],[1,4,5,6,7]])"
1000000 loops, best of 3: 1.58 usec per loop
:~$ python -m timeit"reduce(lambda x,y :x+y ,[[1,2,3],[1,2],[1,4,5,6,7]])"
1000000 loops, best of 3: 0.791 usec per loop
:~$ python -m timeit"[j for i in [[1,2,3],[1,2],[1,4,5,6,7]] for j in i]"
1000000 loops, best of 3: 0.784 usec per loop

@will's answer上使用sum的基准(其快速适用于短名单,但不适用于长名单):

1
2
3
4
5
6
:~$ python -m timeit"sum([[1,2,3],[4,5,6],[7,8,9]], [])"
1000000 loops, best of 3: 0.575 usec per loop
:~$ python -m timeit"sum([range(100),range(100)], [])"
100000 loops, best of 3: 2.27 usec per loop
:~$ python -m timeit"reduce(lambda x,y :x+y ,[range(100),range(100)])"
100000 loops, best of 3: 2.1 usec per loop


对于这样一个列表,我最喜欢的小技巧就是使用sum

sum有一个可选的参数:sum(iterable [, start]),所以可以这样做:

1
2
list_of_lists = [[1,2,3], [4,5,6], [7,8,9]]
print sum(list_of_lists, []) # [1,2,3,4,5,6,7,8,9]

这是因为+运算符恰好是列表的串联运算符,并且您告诉它起始值是[]—一个空列表。

但是关于sum的文档建议您使用itertools.chain,因为它更清楚。


这将在您的特定情况下起作用。如果您有多个层次的嵌套iterables,递归函数将工作得最好。

1
2
3
4
5
6
def flatten(input):
    new_list = []
    for i in input:
        for j in i:
            new_list.append(j)
    return new_list