python 的多层 list 展平为一层

在使用 python 时,有时候需要将多层 list 处理为单层的,本文对这个操作的方法进行总结

方法 1: 使用两次 for 循环

1
2
3
4
5
6
7
8
9
# forfor
>>> demolist1
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> demolist2
[ [1, 2], 3], [[4, 5], 6], [[7, 8], 9]]
>>> [item for sublist in demolist1 for item in sublist]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> [item for sublist in demolist2 for item in sublist]
[[1, 2], 3, [4, 5], 6, [7, 8], 9]

方法 2:通过 sum

1
2
3
4
5
6
7
8
9
# sum_brackets
>>> demolist1
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> demolist2
[[[1, 2], 3], [[4, 5], 6], [[7, 8], 9]]
>>> sum(demolist1,[])
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> sum(demolist2,[])
[[1, 2], 3, [4, 5], 6, [7, 8], 9] // sum可以解开第2层

方法 3:使用 functools 內建模块

1
2
3
4
5
6
7
8
9
10
11
# functools_reduce
>>> import functools
>>> import operator
>>> demolist1
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> demolist2
[[[1, 2], 3], [[4, 5], 6], [[7, 8], 9]]
>>> functools.reduce(operator.concat, demolist1)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> functools.reduce(operator.concat, demolist2)
[[1, 2], 3, [4, 5], 6, [7, 8], 9]

方法 4:使用 itertools 內建模块

1
2
3
4
5
6
7
8
9
10
# itertools_chain
>>> import itertools
>>> demolist1
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> demolist2
[[[1, 2], 3], [[4, 5], 6], [[7, 8], 9]]
>>> list(itertools.chain.from_iterable(demolist1))
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(itertools.chain.from_iterable(demolist2))
[[1, 2], 3, [4, 5], 6, [7, 8], 9]

方法 5:使用 numpy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>>> import numpy
>>> demolist1
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> demolist2
[[[1, 2], 3], [[4, 5], 6], [[7, 8], 9]]
# numpy_concatenate
>>> list(numpy.concatenate(demolist1))
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(numpy.concatenate(demolist2))
:6: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray
[[1, 2], 3, [4, 5], 6, [7, 8], 9]
# numpy_flat
>>> list(numpy.array(demolist1).flat)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(numpy.array(demolist2).flat)
__main__:1: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray
[[1, 2], 3, [4, 5], 6, [7, 8], 9]

方法 6:自定义函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
>>> from collections import Iterable 
__main__:1: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated since Python 3.3,and in 3.9 it will stop working
>>> demolist1
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> demolist2
[[[1, 2], 3], [[4, 5], 6], [[7, 8], 9]]
# pylangs_flatten
>>> def flatten(items):
... """Yield items from any nested iterable; see REF."""
... for x in items:
... if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
... yield from flatten(x)
... else:
... yield x
...
>>> list(flatten(demolist1))
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(flatten(demolist2))
[1, 2, 3, 4, 5, 6, 7, 8, 9]

方法 7:使用库 iteration_utilities

1
2
def iteration_utilities_deepflatten(a):
return list(deepflatten(a, depth=1))

耗时比较

1
2
3
4
5
6
7
8
9
10
11
12
13
import matplotlib.pyplot as plt
from simple_benchmark import benchmark
#基准测试
b = benchmark(
[forfor, sum_brackets, functools_reduce, itertools_chain,numpy_flat, numpy_concatenate, pylangs_flatten,iteration_utilities_deepflatten],
arguments={2**i: [[0]*5]*(2**i) for i in range(1, 13)},
argument_name='number of inner lists'
)
#显示测试结果
plt.subplots(1,1,figsize=(15,10))
b.plot()
plt.legend(loc = 'upper left')
plt.show()

python的多层list展平为一层-20250116142027