如何从列表列表中制作出一份平面列表?

2024-11-15 08:36:00
admin
原创
13
摘要:问题描述:我有一系列的列表,例如[ [1, 2, 3], [4, 5, 6], [7], [8, 9] ] 我怎样才能将其展平以获得[1, 2, 3, 4, 5, 6, 7, 8, 9]?如果您的列表列表来自嵌套列表理解,则可以通过修复理解来更简单/直接地解决问题;请参阅如何从...

问题描述:

我有一系列的列表,例如

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

我怎样才能将其展平以获得[1, 2, 3, 4, 5, 6, 7, 8, 9]


如果您的列表列表来自嵌套列表理解,则可以通过修复理解来更简单/直接地解决问题;请参阅如何从列表理解而不是嵌套列表中获得平坦结果?

这里最流行的解决方案通常只展平嵌套列表的一个“级别”。请参阅展平不规则(任意嵌套)列表列表,了解完全展平深层嵌套结构(一般以递归方式)的解决方案。


解决方案 1:

xss可以使用嵌套列表推导来展平命名列表的列表:

flat_list = [
    x
    for xs in xss
    for x in xs
]

以上相当于:

flat_list = []

for xs in xss:
    for x in xs:
        flat_list.append(x)

对应的函数如下:

def flatten(xss):
    return [x for xs in xss for x in xs]

这是最快的方法。作为证据,使用timeit标准库中的模块,我们看到:

$ python -mtimeit -s'xss=[[1,2,3],[4,5,6],[7],[8,9]]*99' '[x for xs in xss for x in xs]'
10000 loops, best of 3: 143 usec per loop

$ python -mtimeit -s'xss=[[1,2,3],[4,5,6],[7],[8,9]]*99' 'sum(xss, [])'
1000 loops, best of 3: 969 usec per loop

$ python -mtimeit -s'xss=[[1,2,3],[4,5,6],[7],[8,9]]*99' 'reduce(lambda xs, ys: xs + ys, xss)'
1000 loops, best of 3: 1.1 msec per loop

解释:基于 的方法+(包括 中的隐含使用sum)是当有 L 个子列表时所必需的O(L**2)——随着中间结果列表变得越来越长,每一步都会分配一个新的中间结果列表对象,并且必须复制前一个中间结果中的所有项目(以及在最后添加的一些新项目)。因此,为了简单起见并且不失一般性,假设您有 L 个子列表,每个子列表有 M 个项目:第一个 M 个项目来回复制L-1次,第二个 M 个项目L-2次,依此类推;总副本数是 x 之和的 M 倍(不包括 1 到 L 的 x),即M * (L**2)/2

列表推导仅生成一个列表,并且将每个项目(从其原始位置到结果列表)复制一次。

解决方案 2:

您可以使用itertools.chain()

>>> import itertools
>>> list2d = [[1,2,3], [4,5,6], [7], [8,9]]
>>> merged = list(itertools.chain(*list2d))

或者你可以使用itertools.chain.from_iterable()不需要使用*运算符解包列表:

>>> import itertools
>>> list2d = [[1,2,3], [4,5,6], [7], [8,9]]
>>> merged = list(itertools.chain.from_iterable(list2d))

这种方法可以说比以下方法更具可读性[item for sublist in l for item in sublist]并且似乎也更快:

$ python3 -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99;import itertools' 'list(itertools.chain.from_iterable(l))'
20000 loops, best of 5: 10.8 usec per loop
$ python3 -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 5: 21.7 usec per loop
$ python3 -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'sum(l, [])'
1000 loops, best of 5: 258 usec per loop
$ python3 -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99;from functools import reduce' 'reduce(lambda x,y: x+y,l)'
1000 loops, best of 5: 292 usec per loop
$ python3 --version
Python 3.7.5rc1

解决方案 3:

作者注:这非常低效。但很有趣,因为幺半群很棒。

>>> xss = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
>>> sum(xss, [])
[1, 2, 3, 4, 5, 6, 7, 8, 9]

sum对可迭代对象 的元素求和xss,并使用第二个参数作为[]和的初始值。(默认初始值是0,它不是列表。)

因为您正在对嵌套列表求和,所以您实际上得到[1,3]+[2,4]的是 的结果sum([[1,3],[2,4]],[]),它等于[1,3,2,4]

请注意,这仅适用于列表的列表。对于列表的列表的列表,您需要另一种解决方案。

解决方案 4:

我使用perfplot(我的一个小项目,本质上是一个包装器timeit)测试了大多数建议的解决方案,并发现

import functools
import operator
functools.reduce(operator.iconcat, a, [])

是最快的解决方案,无论是连接许多小列表还是连接少数长列表时。 (operator.iadd同样快。)

一个更简单且可接受的变体是

out = []
for sublist in a:
    out.extend(sublist)

如果子列表的数量很大,则其性能会比上述建议稍差。

在此处输入图片描述

在此处输入图片描述


重现情节的代码:

import functools
import itertools
import operator

import numpy as np
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(np.array(a).flat)


def numpy_concatenate(a):
    return list(np.concatenate(a))


def extend(a):
    out = []
    for sublist in a:
        out.extend(sublist)
    return out


b = perfplot.bench(
    setup=lambda n: [list(range(10))] * n,
    # setup=lambda n: [list(range(n))] * 10,
    kernels=[
        forfor,
        sum_brackets,
        functools_reduce,
        functools_reduce_iconcat,
        itertools_chain,
        numpy_flat,
        numpy_concatenate,
        extend,
    ],
    n_range=[2 ** k for k in range(16)],
    xlabel="num lists (of length 10)",
    # xlabel="len lists (10 lists total)"
)
b.save("out.png")
b.show()

解决方案 5:

使用functools.reduce,将累积列表添加xs到下一个列表ys

from functools import reduce
xss = [[1,2,3], [4,5,6], [7], [8,9]]
out = reduce(lambda xs, ys: xs + ys, xss)

输出:

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

一种更快捷的方法是使用operator.concat

from functools import reduce
import operator
xss = [[1,2,3], [4,5,6], [7], [8,9]]
out = reduce(operator.concat, xss)

输出:

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

解决方案 6:

这是适用于嵌套混合容器中的对象(例如数字字符串)的通用方法。这可以展平简单和复杂的容器(另请参阅演示)。

代码

from typing import Iterable 
#from collections import Iterable                            # < py38


def flatten(items):
    """Yield items from any nested iterable; see Reference."""
    for x in items:
        if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
            for sub_x in flatten(x):
                yield sub_x
        else:
            yield x

注意

  • 在 Python 3 中,yield from flatten(x)可以替换for sub_x in flatten(x): yield sub_x

  • 在 Python 3.8 中,抽象基类从移至collection.abc模块typing

演示

simple = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
list(flatten(simple))
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

complicated = [[1, [2]], (3, 4, {5, 6}, 7), 8, "9"]              # numbers, strs, nested & mixed
list(flatten(complicated))
# [1, 2, 3, 4, 5, 6, 7, 8, '9']

参考

  • 此解决方案根据 Beazley,D. 和 B. Jones 的食谱修改而成。食谱 4.14,Python Cookbook 第 3 版,O'Reilly Media Inc. Sebastopol,CA:2013 年。

  • 发现了一个早期的SO 帖子,可能是原始的演示。

解决方案 7:

要展平深度嵌套的数据结构,请使用1:iteration_utilities.deepflatten

>>> from iteration_utilities import deepflatten

>>> l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
>>> list(deepflatten(l, depth=1))
[1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> l = [[1, 2, 3], [4, [5, 6]], 7, [8, 9]]
>>> list(deepflatten(l))
[1, 2, 3, 4, 5, 6, 7, 8, 9]

它是一个生成器,因此您需要将结果转换为list或明确地对其进行迭代。


要仅展平一个级别,并且如果每个项目本身都是可迭代的,您还可以使用iteration_utilities.flatten它本身只是一个薄包装itertools.chain.from_iterable

>>> from iteration_utilities import flatten
>>> l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
>>> list(flatten(l))
[1, 2, 3, 4, 5, 6, 7, 8, 9]

仅添加一些时间(基于Nico Schlömer 的回答,其中未包含该答案中介绍的功能):

在此处输入图片描述

这是对数对数图,用于适应跨度巨大的值范围。对于定性推理:值越低越好。

结果表明,如果可迭代对象仅包含几个内部可迭代对象,那么sum速度会最快,但是对于长可迭代对象itertools.chain.from_iterable,只有iteration_utilities.deepflatten或嵌套理解具有合理的性能并且itertools.chain.from_iterable速度最快(正如 Nico Schlömer 已经注意到的那样)。

from itertools import chain
from functools import reduce
from collections import Iterable  # or from collections.abc import Iterable
import operator
from iteration_utilities import deepflatten

def nested_list_comprehension(lsts):
    return [item for sublist in lsts for item in sublist]

def itertools_chain_from_iterable(lsts):
    return list(chain.from_iterable(lsts))

def pythons_sum(lsts):
    return sum(lsts, [])

def reduce_add(lsts):
    return reduce(lambda x, y: x + y, lsts)

def pylangs_flatten(lsts):
    return list(flatten(lsts))

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

def reduce_concat(lsts):
    return reduce(operator.concat, lsts)

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


from simple_benchmark import benchmark

b = benchmark(
    [nested_list_comprehension, itertools_chain_from_iterable, pythons_sum, reduce_add,
     pylangs_flatten, reduce_concat, iteration_utilities_deepflatten],
    arguments={2**i: [[0]*5]*(2**i) for i in range(1, 13)},
    argument_name='number of inner lists'
)

b.plot()

1 免责声明:我是该库的作者

解决方案 8:

以下内容对我来说似乎最简单:

>>> import numpy as np
>>> l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
>>> print(np.concatenate(l))
[1 2 3 4 5 6 7 8 9]

解决方案 9:

考虑安装该more_itertools包。

> pip install more_itertools

它附带了一个实现flatten(来源,来自itertools 食谱):

import more_itertools


lst = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
list(more_itertools.flatten(lst))
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

注意:如文档中所述,flatten需要列表列表。请参阅下文有关展平更多不规则输入的信息。


从 2.4 版开始,你可以使用more_itertools.collapse(来源,由 abarnet 贡献)展平更复杂、嵌套的可迭代对象。

lst = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
list(more_itertools.collapse(lst)) 
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

lst = [[1, 2, 3], [[4, 5, 6]], [[[7]]], 8, 9]              # complex nesting
list(more_itertools.collapse(lst))
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

解决方案 10:

根据您的列表[[1, 2, 3], [4, 5, 6], [7], [8, 9]](1 个列表级别),我们可以简单地使用sum(list,[])而不使用任何库

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

当内部存在元组或数字时,扩展此方法的优势。只需将每个元素的映射函数添加map到列表中即可

#For only tuple
sum(list(map(list,[[1, 2, 3], (4, 5, 6), (7,), [8, 9]])),[])
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

#In general

def convert(x):
    if type(x) is int or type(x) is float:
           return [x]
    else:
           return list(x)

sum(list(map(convert,[[1, 2, 3], (4, 5, 6), 7, [8, 9]])),[])
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

在这里,清楚地解释了这种方法在内存方面的缺点。简而言之,它以递归方式创建列表对象,这应该避免 :(

解决方案 11:

您的函数不起作用的原因是,extend就地扩展了一个数组,但没有返回它。您仍然可以从 lambda 返回 x,使用如下方法:

reduce(lambda x,y: x.extend(y) or x, l)

注意:在列表上,extend 比 + 更有效。

解决方案 12:

matplotlib.cbook.flatten()适用于嵌套列表,即使它们的嵌套深度比示例更深。

import matplotlib
l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
print(list(matplotlib.cbook.flatten(l)))
l2 = [[1, 2, 3], [4, 5, 6], [7], [8, [9, 10, [11, 12, [13]]]]]
print(list(matplotlib.cbook.flatten(l2)))

结果:

[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

这比 underscore._.flatten 快 18 倍:

Average time over 1000 trials of matplotlib.cbook.flatten: 2.55e-05 sec
Average time over 1000 trials of underscore._.flatten: 4.63e-04 sec
(time for underscore._)/(time for matplotlib.cbook) = 18.1233394636

解决方案 13:

你也可以使用 NumPy 的flat:

import numpy as np
list(np.array(l).flat)

它仅当子列表具有相同的尺寸时才有效。

解决方案 14:

你可以使用这个list extend方法。它显示是最快的:

flat_list = []
for sublist in l:
    flat_list.extend(sublist)

表现:

import functools
import itertools
import numpy
import operator
import perfplot


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 extend(a):
    n = []

    list(map(n.extend, a))

    return n


perfplot.show(
    setup = lambda n: [list(range(10))] * n,
    kernels = [
        functools_reduce_iconcat, extend, itertools_chain, numpy_flat
        ],
    n_range = [2**k for k in range(16)],
    xlabel = 'num lists',
    )

输出:

在此处输入图片描述

解决方案 15:

有几个答案使用与下面相同的递归附加方案,但没有一个使用try,这使得解决方案更加健壮和Pythonic

def flatten(itr):
    for x in itr:
        try:
            yield from flatten(x)
        except TypeError:
            yield x

用法:这是一个生成器,您通常希望将其包含在可迭代构建器中list()tuple()或在循环中使用它for

该解决方案的优点是:

  • 适用于任何类型的可迭代对象(甚至是未来的可迭代对象!)

  • 适用于任意组合和嵌套深度

  • 如果顶层包含裸物品也有效

  • 无依赖性

  • 快速高效(你可以部分展平嵌套的可迭代对象,而不必在不需要的剩余部分上浪费时间)

  • 多功能(你可以用它来构建你选择的可迭代对象或在循环中构建)

注意:由于所有可迭代对象都是扁平化的,因此字符串会被分解为单个字符的序列。如果您不喜欢/不想要这种行为,可以使用以下版本,该版本会过滤掉扁平化可迭代对象(如字符串和字节):

def flatten(itr):
    if type(itr) in (str,bytes):
        yield itr
    else:
        for x in itr:
            try:
                yield from flatten(x)
            except TypeError:
                yield x

解决方案 16:

注意:以下内容适用于 Python 3.3+,因为它使用yield_fromsix也是一个第三方包,尽管它很稳定。或者,您可以使用sys.version


对于 的情况obj = [[1, 2,], [3, 4], [5, 6]],这里的所有解决方案都很好,包括列表理解和itertools.chain.from_iterable

但是,请考虑这个稍微复杂一点的情况:

>>> obj = [[1, 2, 3], [4, 5], 6, 'abc', [7], [8, [9, 10]]]

这里有几个问题:

  • 一个元素6,只是一个标量;它是不可迭代的,所以上述路线在这里会失败。

  • 从技术上讲,元素可迭代的(所有s 都是)。但是,仔细阅读一下,您不想这样对待它——您想将其视为单个元素'abc'str

  • 最后一个元素[8, [9, 10]]本身就是一个嵌套的可迭代对象。基本列表理解,chain.from_iterable仅提取“向下 1 级”。

您可以按照下列方法解决此问题:

>>> from collections import Iterable
>>> from six import string_types

>>> def flatten(obj):
...     for i in obj:
...         if isinstance(i, Iterable) and not isinstance(i, string_types):
...             yield from flatten(i)
...         else:
...             yield i


>>> list(flatten(obj))
[1, 2, 3, 4, 5, 6, 'abc', 7, 8, 9, 10]

在这里,您检查子元素 (1) 是否可以使用 进行迭代Iterable,即 的 ABC itertools,但还想确保 (2) 该元素不是类似字符串的”。

解决方案 17:

如果您愿意为了更整洁的外观而放弃一点点速度,那么您可以使用numpy.concatenate().tolist()numpy.concatenate().ravel().tolist()

import numpy

l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]] * 99

%timeit numpy.concatenate(l).ravel().tolist()
1000 loops, best of 3: 313 µs per loop

%timeit numpy.concatenate(l).tolist()
1000 loops, best of 3: 312 µs per loop

%timeit [item for sublist in l for item in sublist]
1000 loops, best of 3: 31.5 µs per loop

您可以在文档numpy.concatenate和numpy.ravel中找到更多信息。

解决方案 18:

def flatten(alist):
    if alist == []:
        return []
    elif type(alist) is not list:
        return [alist]
    else:
        return flatten(alist[0]) + flatten(alist[1:])

解决方案 19:

我想要一个可以处理多重嵌套([[1], [[[2]], [3]]], [1, 2, 3]例如)的解决方案,但也不会是递归的(我有一个很大的递归级别,并且我得到了递归错误。

这就是我想出的:

def _flatten(l) -> Iterator[Any]:
    stack = l.copy()
    while stack:
        item = stack.pop()
        if isinstance(item, list):
            stack.extend(item)
        else:
            yield item


def flatten(l) -> Iterator[Any]:
    return reversed(list(_flatten(l)))

和测试:

@pytest.mark.parametrize('input_list, expected_output', [
    ([1, 2, 3], [1, 2, 3]),
    ([[1], 2, 3], [1, 2, 3]),
    ([[1], [2], 3], [1, 2, 3]),
    ([[1], [2], [3]], [1, 2, 3]),
    ([[1], [[2]], [3]], [1, 2, 3]),
    ([[1], [[[2]], [3]]], [1, 2, 3]),
])
def test_flatten(input_list, expected_output):
    assert list(flatten(input_list)) == expected_output

解决方案 20:

这可能不是最有效的方法,但我想用一行代码(实际上是两行代码)。两个版本都可以在任意层次嵌套列表上工作,并利用语言特性(Python 3.5)和递归。

def make_list_flat (l):
    flist = []
    flist.extend ([l]) if (type (l) is not list) else [flist.extend (make_list_flat (e)) for e in l]
    return flist

a = [[1, 2], [[[[3, 4, 5], 6]]], 7, [8, [9, [10, 11], 12, [13, 14, [15, [[16, 17], 18]]]]]]
flist = make_list_flat(a)
print (flist)

输出为

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]

这是深度优先的方式。递归一直向下,直到找到非列表元素,然后扩展局部变量flist,然后将其回滚到父级。每当flist返回时,它都会扩展到flist列表理解中的父级。因此,在根部,返回一个平面列表。

上面的代码创建了几个本地列表并返回它们,用于扩展父级列表。我认为解决这个问题的办法可能是创建一个全局列表flist,如下所示。

a = [[1, 2], [[[[3, 4, 5], 6]]], 7, [8, [9, [10, 11], 12, [13, 14, [15, [[16, 17], 18]]]]]]
flist = []
def make_list_flat (l):
    flist.extend ([l]) if (type (l) is not list) else [make_list_flat (e) for e in l]

make_list_flat(a)
print (flist)

输出再次

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]

尽管我目前还不确定其效率。

解决方案 21:

如果您想要解除所有内容的嵌套并保留一个不同的元素列表,您也可以使用它。

list_of_lists = [[1,2], [2,3], [3,4]]
list(set.union(*[set(s) for s in list_of_lists]))

解决方案 22:

这是我在其他答案中没有看到的方法。它支持任何级别的嵌套,可迭代工作且无需库:

mylist = [[1,2,4,5],[[0,8,9],5,7],[3,11,[44,45,46],25]]

for i,_ in enumerate(mylist):          # indexes, including extended positions
    while isinstance(mylist[i],list):  # drill down/extend current position
        mylist[i:i+1] = mylist[i]      # as long as item is a list

print(mylist)
[1, 2, 4, 5, 0, 8, 9, 5, 7, 3, 11, 44, 45, 46, 25]

解决方案 23:

我建议使用带有Yield语句和Yield from 的生成器。

以下是一个例子:

from collections.abc import Iterable

def flatten(items, ignore_types=(bytes, str)):
    """
       Flatten all of the nested lists to the one. Ignoring flatting of iterable types str and bytes by default.
    """
    for x in items:
        if isinstance(x, Iterable) and not isinstance(x, ignore_types):
            yield from flatten(x)
        else:
            yield x

values = [7, [4, 3, 5, [7, 3], (3, 4), ('A', {'B', 'C'})]]

for v in flatten(values):
    print(v)

解决方案 24:

另一种不寻常的方法适用于异构和同构整数列表:

from typing import List


def flatten(l: list) -> List[int]:
    """Flatten an arbitrary deep nested list of lists of integers.

    Examples:
        >>> flatten([1, 2, [1, [10]]])
        [1, 2, 1, 10]

    Args:
        l: Union[l, Union[int, List[int]]

    Returns:
        Flatted list of integer
    """
    return [int(i.strip('[ ]')) for i in str(l).split(',')]

解决方案 25:

一个非递归函数,用于展平任意深度的列表列表:

def flatten_list(list1):
    out = []
    inside = list1
    while inside:
        x = inside.pop(0)
        if isinstance(x, list):
            inside[0:0] = x
        else:
            out.append(x)
    return out

l = [[[1,2],3,[4,[[5,6],7],[8]]],[9,10,11]]
flatten_list(l)
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

解决方案 26:

不是一行,但看到这里所有的答案,我猜这个长列表错过了一些模式匹配,所以在这里:)

这两种方法可能效率不高,但无论如何,它很容易阅读(至少对我来说;也许我被函数式编程宠坏了):

def flat(x):
    match x:
        case []:
            return []
        case [[*sublist], *r]:
            return [*sublist, *flat(r)]

第二个版本考虑列表的列表的列表......无论嵌套如何:

def flat(x):
    match x:
        case []:
            return []
        case [[*sublist], *r]:
            return [*flat(sublist), *flat(r)]
        case [h, *r]:
            return [h, *flat(r)]

解决方案 27:

如果你有一个 numpy 数组a

a = np.array([[1,2], [3,4]])
a.flatten('C')

生成:

[1, 2, 3, 4]

np.flatten还接受其他参数:

  • C

  • F

  • A

  • K

有关参数的更多详细信息请参见此处。

解决方案 28:

如果我想在之前的回答中添加一些内容,那么这里是我的递归flatten函数,它不仅可以展平嵌套列表,还可以展平任何给定的容器或通常可以抛出项目的任何对象。这也适用于任何深度的嵌套,它是一个惰性迭代器,可以根据要求生成项目:

def flatten(iterable):
    # These types won't considered a sequence or generally a container
    exclude = str, bytes

    for i in iterable:
        try:
            if isinstance(i, exclude):
                raise TypeError
            iter(i)
        except TypeError:
            yield i
        else:
            yield from flatten(i)

这样,您可以排除您不想被扁平化的类型,例如str或其他什么。

这个想法是,如果一个对象可以传递,iter()它就可以产生项目。因此,可迭代对象甚至可以将生成器表达式作为项目。

有人可能会争辩:既然 OP 没有要求,你为什么要写这么笼统的内容?好吧,你是对的。我只是觉得这可能会对某些人有所帮助(就像它对我一样)。

测试用例:

lst1 = [1, {3}, (1, 6), [[3, 8]], [[[5]]], 9, ((((2,),),),)]
lst2 = ['3', B'A', [[[(i ** 2 for i in range(3))]]], range(3)]

print(list(flatten(lst1)))
print(list(flatten(lst2)))

输出:

[1, 3, 1, 6, 3, 8, 5, 9, 2]
['3', b'A', 0, 1, 4, 0, 1, 2]

解决方案 29:

parsel.utils.flatten在平展多层列表嵌套时非常有用。我发现它有助于避免NumPy的开销。

为了简单起见,我在这里使用数字,但我主要将它与字符串一起使用,这对于我的目的来说运行得非常快(200 个嵌套列表,每个列表大约有 40 个元素)。

nested_list = [[1, 2, [3, 4]], [5, [6, [7, 8]]]]
flattened_list = parsel.utils.flatten(nested_list)
print(flattened_list)
-> [1, 2, 3, 4, 5, 6, 7, 8]

解决方案 30:

我喜欢添加一个高性能生成器解决方案,它可以扩充任何深度的嵌套列表(或任何类型的可迭代对象) (仅限二维列表):

from itertools import chain

def flatten_deep_generator(iterable):
    iterator = iter(iterable)
    try:
        while 1: # StopIteration will break the loop
            item = next(iterator)
            # Check if item contains sub-items
            if not hasattr(item,'__trunc__'):
                iterator = chain(iter(item), iterator)
            else:
                yield item
    except StopIteration:
        pass

根据您的需要,生成器比列表具有巨大的优势。例如,如果您想filter()在之后添加函数。只有在构建了完整的生成器(包括过滤)后,才应在最后实例化结果列表,这样可以避免对项目进行多次迭代。

备注:与其他提出的生成器解决方案相比,这是一个迭代而不是递归解决方案,可避免深度嵌套迭代时出现 RecursionErrors。

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用