如何在不使用 numpy 的情况下将 2D 列表展平为 1D? [复制]

Posted

技术标签:

【中文标题】如何在不使用 numpy 的情况下将 2D 列表展平为 1D? [复制]【英文标题】:how to flatten a 2D list to 1D without using numpy? [duplicate] 【发布时间】:2015-05-28 10:51:06 【问题描述】:

我有一个如下所示的列表:

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

我想把它展平成[1,2,3,1,2,1,4,5,6,7]

有没有不使用 numpy 的轻量级函数?

【问题讨论】:

【参考方案1】:

如果没有 numpy (ndarray.flatten),一种方法是使用 chain.from_iterable,它是 itertools.chain 的替代构造函数:

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

或者作为另一种 Pythonic 方法,您可以使用 列表推导

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

另一种非常适合短列表的函数式方法也可以是 Python2 中的 reduce 和 Python3 中的 functools.reduce不要将它用于长列表):

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

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)

基准:

:~$ 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

使用sum 的@Will 答案的基准测试(对于短名单来说很快,但对于长名单来说却不是):

:~$ 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([[1,2,3],[4,5,6],[7,8,9]], []) 与这些相比如何? @will 对于短列表比 reduce 更快,但对于更长的列表则不然! @Kasramvd 很棒的回应!但是我对像[j for i in [[1,2,3],[1,2],[1,4,5,6,7]] for j in i] 这样的非嵌套列表理解如何使二维列表变平感到困惑,您能否提供更多说明? @WeisiZhan 这种列表推导通常被称为嵌套,因为嵌套了for 循环。为了理解此类列表推导的行为,您可以使用嵌套的 for lop 并将所有项目附加到先前定义的列表中。喜欢,lst = []; for sublist in all_lists: for item in sublist: lst.append(item) @Kasramvd 谢谢! :-)【参考方案2】:

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

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

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,因为它更清晰。

【讨论】:

字符串列表怎么办? @pyd 上面的代码适用于任何对象类型...为什么不在询问之前先测试一下? my_list 看起来像 ["A",["B","C"],"D",["E","F"]] 它不起作用, @pyd 它不起作用,因为 "A" 不是一个列表,但是 ["B","C"] 是这样,当它尝试使用 + 连接它们时它失败了(你不能将字符串添加到列表中) sum中使用+作为串联,简直是奇迹。谢谢你。这是任何列表列表的绝佳解决方案。【参考方案3】:

这将适用于您的特定情况。如果您有多个级别的嵌套迭代,递归函数将最有效。

def flatten(input):
    new_list = []
    for i in input:
        for j in i:
            new_list.append(j)
    return new_list

【讨论】:

这是唯一真正适用于深度嵌套列表的解决方案。

以上是关于如何在不使用 numpy 的情况下将 2D 列表展平为 1D? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

如何在不复制数据的情况下将 cv::Mat 转换为 2d std::vector

如何在不使用 foreach 的情况下将 ArrayList 转换为强类型泛型列表?

如何在不使用 for 循环的情况下将列表中的所有项目与整数进行比较

如何在不知道其宽度的情况下将 ul li 列表居中? (分页)

如何在不跟踪索引的情况下将元素附加到列表?

如何在没有来自 Kinect Window SDK 的 Coordinatemapper 的情况下将 3D 骨骼关节映射回 2D 彩色图像