展平不规则(任意嵌套)列表列表

2024-11-15 08:36:00
admin
原创
16
摘要:问题描述:是的,我知道这个主题之前已经讨论过:Python 习语如何链接(展平)有限可迭代对象的无限可迭代对象?在 Python 中展平浅列表如何理解扁平化序列序列?如何从列表列表中制作出一份平面列表?但据我所知,除一个解决方案外,所有解决方案都在像 这样的列表上失败[[[1, 2, 3], [4, 5]],...

问题描述:

是的,我知道这个主题之前已经讨论过:

  • Python 习语如何链接(展平)有限可迭代对象的无限可迭代对象?

  • 在 Python 中展平浅列表

  • 如何理解扁平化序列序列?

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

但据我所知,除一个解决方案外,所有解决方案都在像 这样的列表上失败[[[1, 2, 3], [4, 5]], 6],其中所需的输出是[1, 2, 3, 4, 5, 6](或者甚至更好,一个迭代器)。

我看到的唯一适用于任意嵌套的解决方案可以在这个问题中找到:

def flatten(x):
    result = []
    for el in x:
        if hasattr(el, "__iter__") and not isinstance(el, basestring):
            result.extend(flatten(el))
        else:
            result.append(el)
    return result

这是最好的方法吗?我忽略了什么吗?有什么问题吗?


解决方案 1:

使用生成器函数可以让你的示例更易于阅读并提高性能。

Python 2

使用2.6版本新增的IterableABC:

from collections import Iterable

def flatten(xs):
    for x in xs:
        if isinstance(x, Iterable) and not isinstance(x, basestring):
            for item in flatten(x):
                yield item
        else:
            yield x

Python 3

在 Python 3 中,basestring不再有,但元组(str, bytes)具有相同的效果。此外,yield from运算符每次从生成器返回一个项。

from collections.abc import Iterable

def flatten(xs):
    for x in xs:
        if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
            yield from flatten(x)
        else:
            yield x

解决方案 2:

我的解决方案:

import collections


def flatten(x):
    if isinstance(x, collections.Iterable):
        return [a for i in x for a in flatten(i)]
    else:
        return [x]

简洁一点,但基本上是一样的。

解决方案 3:

使用递归和鸭子类型的生成器(针对 Python 3 更新):

def flatten(L):
    for item in L:
        try:
            yield from flatten(item)
        except TypeError:
            yield item

list(flatten([[[1, 2, 3], [4, 5]], 6]))
>>>[1, 2, 3, 4, 5, 6]

解决方案 4:

这是我的递归 flatten 函数版本,它既能处理元组,也能处理列表,并允许您添加任意位置参数组合。返回一个按顺序逐个参数生成整个序列的生成器:

flatten = lambda *n: (e for a in n
    for e in (flatten(*a) if isinstance(a, (tuple, list)) else (a,)))

用法:

l1 = ['a', ['b', ('c', 'd')]]
l2 = [0, 1, (2, 3), [[4, 5, (6, 7, (8,), [9]), 10]], (11,)]
print list(flatten(l1, -2, -1, l2))
['a', 'b', 'c', 'd', -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

解决方案 5:

@unutbu 非递归解决方案的生成器版本,按照@Andrew 在评论中的要求:

def genflat(l, ltypes=collections.Sequence):
    l = list(l)
    i = 0
    while i < len(l):
        while isinstance(l[i], ltypes):
            if not l[i]:
                l.pop(i)
                i -= 1
                break
            else:
                l[i:i + 1] = l[i]
        yield l[i]
        i += 1

该生成器的稍微简化的版本:

def genflat(l, ltypes=collections.Sequence):
    l = list(l)
    while l:
        while l and isinstance(l[0], ltypes):
            l[0:1] = l[0]
        if l: yield l.pop(0)

解决方案 6:

此版本flatten避免了 Python 的递归限制(因此可以处理任意深度、嵌套的可迭代对象)。它是一个可以处理字符串和任意可迭代对象(甚至是无限的可迭代对象)的生成器。

import itertools
import collections

def flatten(iterable, ltypes=collections.Iterable):
    remainder = iter(iterable)
    while True:
        try:
            first = next(remainder)
        except StopIteration:
            break
        if isinstance(first, ltypes) and not isinstance(first, (str, bytes)):
            remainder = itertools.chain(first, remainder)
        else:
            yield first

以下是一些演示其用法的示例:

print(list(itertools.islice(flatten(itertools.repeat(1)),10)))
# [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

print(list(itertools.islice(flatten(itertools.chain(itertools.repeat(2,3),
                                       {10,20,30},
                                       'foo bar'.split(),
                                       itertools.repeat(1),)),10)))
# [2, 2, 2, 10, 20, 30, 'foo', 'bar', 1, 1]

print(list(flatten([[1,2,[3,4]]])))
# [1, 2, 3, 4]

seq = ([[chr(i),chr(i-32)] for i in range(ord('a'), ord('z')+1)] + list(range(0,9)))
print(list(flatten(seq)))
# ['a', 'A', 'b', 'B', 'c', 'C', 'd', 'D', 'e', 'E', 'f', 'F', 'g', 'G', 'h', 'H',
# 'i', 'I', 'j', 'J', 'k', 'K', 'l', 'L', 'm', 'M', 'n', 'N', 'o', 'O', 'p', 'P',
# 'q', 'Q', 'r', 'R', 's', 'S', 't', 'T', 'u', 'U', 'v', 'V', 'w', 'W', 'x', 'X',
# 'y', 'Y', 'z', 'Z', 0, 1, 2, 3, 4, 5, 6, 7, 8]

虽然flatten可以处理无限生成器,但不能处理无限嵌套:

def infinitely_nested():
    while True:
        yield itertools.chain(infinitely_nested(), itertools.repeat(1))

print(list(itertools.islice(flatten(infinitely_nested()), 10)))
# hangs

解决方案 7:

Pandas 有一个函数可以做到这一点。正如你提到的,它会返回一个迭代器。

In [1]: import pandas
In [2]: pandas.core.common.flatten([[[1, 2, 3], [4, 5]], 6])
Out[2]: <generator object flatten at 0x7f12ade66200>
In [3]: list(pandas.core.common.flatten([[[1, 2, 3], [4, 5]], 6]))
Out[3]: [1, 2, 3, 4, 5, 6]

解决方案 8:

def flatten(xs):
    res = []
    def loop(ys):
        for i in ys:
            if isinstance(i, list):
                loop(i)
            else:
                res.append(i)
    loop(xs)
    return res

解决方案 9:

这是另一个更有趣的答案......

import re

def Flatten(TheList):
    a = str(TheList)
    b,_Anon = re.subn(r'[[,]]', ' ', a)
    c = b.split()
    d = [int(x) for x in c]

    return(d)

基本上,它将嵌套列表转换为字符串,使用正则表达式去除嵌套语法,然后将结果转换回(扁平化)列表。

解决方案 10:

您可以使用deepflatten第三方包iteration_utilities

>>> from iteration_utilities import deepflatten
>>> L = [[[1, 2, 3], [4, 5]], 6]
>>> list(deepflatten(L))
[1, 2, 3, 4, 5, 6]

>>> list(deepflatten(L, types=list))  # only flatten "inner" lists
[1, 2, 3, 4, 5, 6]

它是一个迭代器,因此您需要对其进行迭代(例如,通过包装它list或在循环中使用它)。在内部,它使用迭代方法而不是递归方法,并且它以 C 扩展的形式编写,因此它比纯 Python 方法更快:

>>> %timeit list(deepflatten(L))
12.6 µs ± 298 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
>>> %timeit list(deepflatten(L, types=list))
8.7 µs ± 139 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

>>> %timeit list(flatten(L))   # Cristian - Python 3.x approach from https://stackoverflow.com/a/2158532/5393381
86.4 µs ± 4.42 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

>>> %timeit list(flatten(L))   # Josh Lee - https://stackoverflow.com/a/2158522/5393381
107 µs ± 2.99 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

>>> %timeit list(genflat(L, list))  # Alex Martelli - https://stackoverflow.com/a/2159079/5393381
23.1 µs ± 710 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

我是该图书馆的作者iteration_utilities

解决方案 11:

尝试创建一个可以在 Python 中展平不规则列表的函数很有趣,但这当然是 Python 的用途(让编程变得有趣)。以下生成器运行良好,但有一些注意事项:

def flatten(iterable):
    try:
        for item in iterable:
            yield from flatten(item)
    except TypeError:
        yield iterable

它将扁平化您可能希望保留的数据类型(例如bytearraybytesstr对象)。此外,代码依赖于从不可迭代对象请求迭代器会引发的事实TypeError

>>> L = [[[1, 2, 3], [4, 5]], 6]
>>> def flatten(iterable):
    try:
        for item in iterable:
            yield from flatten(item)
    except TypeError:
        yield iterable


>>> list(flatten(L))
[1, 2, 3, 4, 5, 6]
>>>

编辑:

我不同意之前的实现。问题在于你不应该能够展平不可迭代的东西。这很令人困惑,并给人留下了错误的印象。

>>> list(flatten(123))
[123]
>>>

以下生成器与第一个生成器几乎相同,但没有尝试展平不可迭代对象的问题。当给它一个不合适的参数时,它会像人们预料的那样失败。

def flatten(iterable):
    for item in iterable:
        try:
            yield from flatten(item)
        except TypeError:
            yield item

使用提供的列表测试生成器工作正常。但是,TypeError当向其提供不可迭代的对象时,新代码将引发。以下示例显示了新行为。

>>> L = [[[1, 2, 3], [4, 5]], 6]
>>> list(flatten(L))
[1, 2, 3, 4, 5, 6]
>>> list(flatten(123))
Traceback (most recent call last):
  File "<pyshell#32>", line 1, in <module>
    list(flatten(123))
  File "<pyshell#27>", line 2, in flatten
    for item in iterable:
TypeError: 'int' object is not iterable
>>>

解决方案 12:

这是一个简单的函数,可以展平任意深度的列表。没有递归,以避免堆栈溢出。

from copy import deepcopy

def flatten_list(nested_list):
    """Flatten an arbitrarily nested list, without recursion (to avoid
    stack overflows). Returns a new list, the original list is unchanged.

    >> list(flatten_list([1, 2, 3, [4], [], [[[[[[[[[5]]]]]]]]]]))
    [1, 2, 3, 4, 5]
    >> list(flatten_list([[1, 2], 3]))
    [1, 2, 3]

    """
    nested_list = deepcopy(nested_list)

    while nested_list:
        sublist = nested_list.pop(0)

        if isinstance(sublist, list):
            nested_list = sublist + nested_list
        else:
            yield sublist

解决方案 13:

在尝试回答此类问题时,您确实需要说明您提出的解决方案的代码的局限性。如果只是关于性能,我不会太在意,但大多数作为解决方案提出的代码(包括已接受的答案)都无法展平任何深度大于 1000 的列表。

当我说大多数代码时,我指的是所有使用任何形式递归的代码(或调用递归的标准库函数)。所有这些代码都失败了,因为对于每次递归调用,(调用)堆栈都会增加一个单位,而(默认)python 调用堆栈的大小为 1000。

如果您不太熟悉调用堆栈,那么以下内容可能会有所帮助(否则您只需滚动到实现

调用堆栈大小和递归编程(地牢类比)

找到宝藏并退出

想象一下,你进入一个带有编号房间的巨大地牢,寻找宝藏。你不知道这个地方,但你有一些关于如何找到宝藏的指示。每个指示都是一个谜语(难度各不相同,但你无法预测它们有多难)。你决定想一点节省时间的策略,你做了两个观察:

  1. 找到宝藏很困难(需要很长时间),因为你必须解开(可能很难的)谜语才能到达那里。

  2. 一旦找到宝藏,返回入口可能很容易,您只需使用另一个方向的相同路径即可(尽管这需要一点记忆来回忆起您的路径)。

进入地牢后,你注意到这里有一本小笔记本。你决定用它记下你解开谜语后离开的每个房间(进入新房间时),这样你就可以返回入口。这是一个天才的想法,你甚至不会花一分钱来实施你的策略。

你进入地牢,成功解决了前 1001 个谜题,但你没有预料到的事情发生了,你借的笔记本已经没有空间了。你决定放弃你的任务,因为你宁愿得不到宝藏,也不愿永远迷失在地牢里(这看起来确实很聪明)。

执行递归程序

基本上,这与寻找宝藏完全相同。地牢是计算机的内存,你现在的目标不是找到宝藏,而是计算某个函数(对于给定的x找到f(x) )。指示只是帮助你解决f(x) 的子例程。你的策略与调用堆栈策略相同,笔记本是堆栈,房间是函数的返回地址:

x = ["over here", "am", "I"]
y = sorted(x) # You're about to enter a room named `sorted`, note down the current room address here so you can return back: 0x4004f4 (that room address looks weird)
# Seems like you went back from your quest using the return address 0x4004f4
# Let's see what you've collected 
print(' '.join(y))

您在地牢中遇到的问题在这里也是一样的,调用堆栈的大小是有限的(这里是 1000),因此,如果您输入了太多函数而不返回,那么您将填满调用堆栈并出现错误,如下所示:“亲爱的冒险家,我很抱歉,但您的笔记本已满”:RecursionError: maximum recursion depth exceeded。请注意,您不需要递归来填充调用堆栈,但非递归程序调用 1000 个函数而不返回的可能性很小。同样重要的是要理解,一旦您从函数返回,调用堆栈就会从使用的地址中释放出来(因此名称为“堆栈”,返回地址在进入函数之前被推入并在返回时被拉出)。在简单递归的特殊情况下(一个f一次又一次调用自身的函数),您将f一次又一次地输入,直到计算完成(直到找到宝藏),然后返回,f直到您回到f最初调用的位置。调用堆栈永远不会被释放任何东西,直到最后它将一个接一个地释放所有的返回地址。

如何避免这个问题?

这其实很简单:“如果你不知道递归能走多远,就不要使用递归”。这并不总是正确的,因为在某些情况下,尾部调用递归可以得到优化(TCO)。但在 Python 中,情况并非如此,即使是“编写良好的”递归函数也不会优化堆栈的使用。Guido 有一篇关于这个问题的有趣帖子:尾部递归消除

有一种技术可以用来使任何递归函数迭代,这种技术我们可以称为自带笔记本。例如,在我们的特定情况下,我们只是在探索一个列表,进入一个房间相当于进入一个子列表,你应该问自己的问题是如何从列表返回到它的父列表?答案并不复杂,重复以下步骤,直到stack为空:

  1. 在进入新子列表时推送当前列表address并放入(请注意,列表地址+索引也是一个地址,因此我们只使用与调用堆栈完全相同的技术);index`stack`

  2. 每次找到一个项目时,yield它(或将其添加到列表中);

  3. stack 一旦列表被完全探索,使用返回address(和index)返回到父列表。

还要注意,这相当于树中的 DFS,其中一些节点是子列表A = [1, 2],一些是简单项:(0, 1, 2, 3, 4对于L = [0, [1,2], 3, 4])。树看起来像这样:

                    L
                    |
           -------------------
           |     |     |     |
           0   --A--   3     4
               |   |
               1   2

DFS 遍历预序为:L、0、A、1、2、3、4。请记住,为了实现迭代 DFS,您还“需要”一个堆栈。我之前提出的实现导致具有以下状态(对于stackflat_list):

init.:  stack=[(L, 0)]
**0**:  stack=[(L, 0)],         flat_list=[0]
**A**:  stack=[(L, 1), (A, 0)], flat_list=[0]
**1**:  stack=[(L, 1), (A, 0)], flat_list=[0, 1]
**2**:  stack=[(L, 1), (A, 1)], flat_list=[0, 1, 2]
**3**:  stack=[(L, 2)],         flat_list=[0, 1, 2, 3]
**3**:  stack=[(L, 3)],         flat_list=[0, 1, 2, 3, 4]
return: stack=[],               flat_list=[0, 1, 2, 3, 4]

在这个例子中,堆栈的最大大小是 2,因为输入列表(以及树)的深度为 2。

执行

对于实现,在 Python 中,你可以通过使用迭代器而不是简单列表来简化一点。对(子)迭代器的引用将用于存储子列表返回地址(而不是同时拥有列表地址和索引)。这并没有太大的区别,但我觉得这更易读(也更快一些):

def flatten(iterable):
    return list(items_from(iterable))

def items_from(iterable):
    cursor_stack = [iter(iterable)]
    while cursor_stack:
        sub_iterable = cursor_stack[-1]
        try:
            item = next(sub_iterable)
        except StopIteration:   # post-order
            cursor_stack.pop()
            continue
        if is_list_like(item):  # pre-order
            cursor_stack.append(iter(item))
        elif item is not None:
            yield item          # in-order

def is_list_like(item):
    return isinstance(item, list)

另外,请注意,在 中is_list_likeisinstance(item, list)可以将其更改为处理更多输入类型,这里我只想使用最简单的版本,其中 (iterable) 只是一个列表。但您也可以这样做:

def is_list_like(item):
    try:
        iter(item)
        return not isinstance(item, str)  # strings are not lists (hmm...) 
    except TypeError:
        return False

这将字符串视为“简单项”,因此flatten_iter([["test", "a"], "b])将返回["test", "a", "b"]和 而不是["t", "e", "s", "t", "a", "b"]。请注意,在这种情况下,iter(item)在每个项上调用两次,我们假装这是读者的练习,以使其更清晰。

对其他实现的测试和评论

最后,请记住,您无法L使用打印无限嵌套列表,因为它在内部将使用对( ) 的print(L)递归调用。出于同样的原因,对involving的解决方案将失败并显示相同的错误消息。__repr__`RecursionError: maximum recursion depth exceeded while getting the repr of an objectflattenstr`

如果您需要测试您的解决方案,您可以使用此函数生成一个简单的嵌套列表:

def build_deep_list(depth):
    """Returns a list of the form $l_{depth} = [depth-1, l_{depth-1}]$
    with $depth > 1$ and $l_0 = [0]$.
    """
    sub_list = [0]
    for d in range(1, depth):
        sub_list = [d, sub_list]
    return sub_list

得到结果为:build_deep_list(5)>>> [4, [3, [2, [1, [0]]]]]

解决方案 14:

尽管已经选择了一个优雅且非常 Pythonic 的答案,但我仍将提出我的解决方案以供审查:

def flat(l):
    ret = []
    for i in l:
        if isinstance(i, list) or isinstance(i, tuple):
            ret.extend(flat(i))
        else:
            ret.append(i)
    return ret

请告诉我这个代码是好是坏?

解决方案 15:

我更喜欢简单的答案。没有生成器。没有递归或递归限制。只有迭代:

def flatten(TheList):
    listIsNested = True

    while listIsNested:                 #outer loop
        keepChecking = False
        Temp = []

        for element in TheList:         #inner loop
            if isinstance(element,list):
                Temp.extend(element)
                keepChecking = True
            else:
                Temp.append(element)

        listIsNested = keepChecking     #determine if outer loop exits
        TheList = Temp[:]

    return TheList

这适用于两个列表:一个内部 for 循环和一个外部 while 循环。

内层 for 循环遍历列表。如果找到列表元素,它会 (1) 使用 list.extend() 将该部分展开一层嵌套,并 (2) 将 keepChecking 切换为 True。keepchecking 用于控制外层 while 循环。如果外层循环设置为 true,它会触发内层循环进行另一次循环。

这些过程一直进行,直到找不到嵌套列表为止。当最终出现一个过程,但未找到任何嵌套列表时,keepChecking 永远不会被触发为 true,这意味着 listIsNested 保持为 false,并且外部 while 循环退出。

然后返回扁平列表。

试运行

flatten([1,2,3,4,[100,200,300,[1000,2000,3000]]])

[1, 2, 3, 4, 100, 200, 300, 1000, 2000, 3000]

解决方案 16:

我没有仔细研究这里所有已有的答案,但这是我想到的一句话,借鉴了 lisp 的第一个和其余列表处理方式

def flatten(l): return flatten(l[0]) + (flatten(l[1:]) if len(l) > 1 else []) if type(l) is list else [l]

这是一个简单的例子,也是一个不那么简单的例子——

>>> flatten([1,[2,3],4])
[1, 2, 3, 4]

>>> flatten([1, [2, 3], 4, [5, [6, {'name': 'some_name', 'age':30}, 7]], [8, 9, [10, [11, [12, [13, {'some', 'set'}, 14, [15, 'some_string'], 16], 17, 18], 19], 20], 21, 22, [23, 24], 25], 26, 27, 28, 29, 30])
[1, 2, 3, 4, 5, 6, {'age': 30, 'name': 'some_name'}, 7, 8, 9, 10, 11, 12, 13, set(['set', 'some']), 14, 15, 'some_string', 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
>>> 

解决方案 17:

我经常使用more_itertools.collapse

# pip install more-itertools
from more_itertools import collapse

out = list(collapse([[[1, 2, 3], [4, 5]], 6]))
# [1, 2, 3, 4, 5, 6]

它直接处理字符串/字节,并且不会将它们解包为单个字符:

list(collapse([[[1, 2, 3, 'abc'], [4, 5]], 6, 'def']))
# [1, 2, 3, 'abc', 4, 5, 6, 'def']

它也可以在给定的嵌套级别停止:

list(collapse([[[1, 2, 3], [4, 5]], 6], levels=1))
# [[1, 2, 3], [4, 5], 6]

完整代码相对简单,并且还使用了递归方法:

def collapse(iterable, base_type=None, levels=None):
    def walk(node, level):
        if (
            ((levels is not None) and (level > levels))
            or isinstance(node, (str, bytes))
            or ((base_type is not None) and isinstance(node, base_type))
        ):
            yield node
            return

        try:
            tree = iter(node)
        except TypeError:
            yield node
            return
        else:
            for child in tree:
                yield from walk(child, level + 1)

    yield from walk(iterable, 0)

解决方案 18:

我不确定这是否一定更快或更有效,但这就是我所做的:

def flatten(lst):
    return eval('[' + str(lst).replace('[', '').replace(']', '') + ']')

L = [[[1, 2, 3], [4, 5]], 6]
print(flatten(L))

此处的函数flatten将列表转换为字符串,取出所有方括号,将方括号重新附加到末尾,然后将其转换回列表。

但是,如果您知道字符串列表中会有方括号,例如[[1, 2], "[3, 4] and [5]"],您就必须做其他事情。

解决方案 19:

只需使用一个funcy库:
pip install funcy

import funcy


funcy.flatten([[[[1, 1], 1], 2], 3]) # returns generator
funcy.lflatten([[[[1, 1], 1], 2], 3]) # returns list

解决方案 20:

没有递归或嵌套循环。几行代码。格式良好且易于阅读:

def flatten_deep(arr: list):
    """ Flattens arbitrarily-nested list `arr` into single-dimensional. """

    while arr:
        if isinstance(arr[0], list):  # Checks whether first element is a list
            arr = arr[0] + arr[1:]  # If so, flattens that first element one level
        else:
            yield arr.pop(0)  # Otherwise yield as part of the flat array

flatten_deep(L)

来自我自己的代码https://github.com/jorgeorpinel/flatten_nested_lists/blob/master/flatten.py

解决方案 21:

以下是compiler.ast.flatten2.7.5 中的实现:

def flatten(seq):
    l = []
    for elt in seq:
        t = type(elt)
        if t is tuple or t is list:
            for elt2 in flatten(elt):
                l.append(elt2)
        else:
            l.append(elt)
    return l

有更好、更快的方法(如果你已经到达这里,那么你已经看到了它们)

另请注意:

自 2.6 版起已弃用: 编译器包已在 Python 3 中删除。

解决方案 22:

我很惊讶没有人想到这一点。该死的递归,我没有得到这里高级人士给出的递归答案。无论如何,这是我对此的尝试。需要注意的是,它非常特定于 OP 的用例

import re

L = [[[1, 2, 3], [4, 5]], 6]
flattened_list = re.sub("[[]]", "", str(L)).replace(" ", "").split(",")
new_list = list(map(int, flattened_list))
print(new_list)

输出:

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

解决方案 23:

我知道已经有很多很棒的答案,但我想添加一个使用函数式编程方法解决问题的答案。在这个答案中,我使用了双重递归:

def flatten_list(seq):
    if not seq:
        return []
    elif isinstance(seq[0],list):
        return (flatten_list(seq[0])+flatten_list(seq[1:]))
    else:
        return [seq[0]]+flatten_list(seq[1:])

print(flatten_list([1,2,[3,[4],5],[6,7]]))

输出:

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

解决方案 24:

我是 Python 新手,有 Lisp 背景。这是我想到的(查看 lulz 的变量名称):

def flatten(lst):
    if lst:
        car,*cdr=lst
        if isinstance(car,(list,tuple)):
            if cdr: return flatten(car) + flatten(cdr)
            return flatten(car)
        if cdr: return [car] + flatten(cdr)
        return [car]

似乎有效。测试:

flatten((1,2,3,(4,5,6,(7,8,(((1,2)))))))

返回:

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

解决方案 25:

我没有看到任何类似的东西发布在这里,只是从关于同一主题的一个封闭式问题来到这里,但为什么不做这样的事情(如果你知道你想要拆分的列表的类型):

>>> a = [1, 2, 3, 5, 10, [1, 25, 11, [1, 0]]]    
>>> g = str(a).replace('[', '').replace(']', '')    
>>> b = [int(x) for x in g.split(',') if x.strip()]

您需要知道元素的类型,但我认为这可以概括,并且就速度而言,我认为它会更快。

解决方案 26:

完全是黑客行为,但我认为它会起作用(取决于你的数据类型)

flat_list = ast.literal_eval("[%s]"%re.sub("[[]]","",str(the_list)))

解决方案 27:

这是另一种 py2 方法,我不确定它是否最快、最优雅、最安​​全......

from collections import Iterable
from itertools import imap, repeat, chain


def flat(seqs, ignore=(int, long, float, basestring)):
    return repeat(seqs, 1) if any(imap(isinstance, repeat(seqs), ignore)) or not isinstance(seqs, Iterable) else chain.from_iterable(imap(flat, seqs))

它可以忽略您想要的任何特定(或派生)类型,它返回一个迭代器,因此您可以将其转换为任何特定容器(如列表、元组、字典)或简单地使用它以减少内存占用,无论好坏,它都可以处理初始不可迭代对象,如 int...

请注意,大部分繁重的工作都是用 C 完成的,因为据我所知,itertools 就是这样实现的,所以虽然它是递归的,但据我所知,它不受 python 递归深度的限制,因为函数调用是在 C 中进行的,但这并不意味着你受到内存的限制,特别是在 OS X 中,它的堆栈大小从今天起有一个硬性限制(OS X Mavericks)...

有一种稍微快一点的方法,但可移植性较差,只有当您能假设输入的基本元素可以明确确定时才使用它,否则,您将得到无限递归,并且由于 OS X 的堆栈大小有限,会很快引发分段错误...

def flat(seqs, ignore={int, long, float, str, unicode}):
    return repeat(seqs, 1) if type(seqs) in ignore or not isinstance(seqs, Iterable) else chain.from_iterable(imap(flat, seqs))

这里我们使用集合来检查类型,因此需要 O(1)与 O(类型数)来检查是否应该忽略元素,当然,任何具有所述忽略类型的派生类型的值都会失败,这就是它使用的原因strunicode所以请谨慎使用它...

测试:

import random

def test_flat(test_size=2000):
    def increase_depth(value, depth=1):
        for func in xrange(depth):
            value = repeat(value, 1)
        return value

    def random_sub_chaining(nested_values):
        for values in nested_values:
            yield chain((values,), chain.from_iterable(imap(next, repeat(nested_values, random.randint(1, 10)))))

    expected_values = zip(xrange(test_size), imap(str, xrange(test_size)))
    nested_values = random_sub_chaining((increase_depth(value, depth) for depth, value in enumerate(expected_values)))
    assert not any(imap(cmp, chain.from_iterable(expected_values), flat(chain(((),), nested_values, ((),)))))

>>> test_flat()
>>> list(flat([[[1, 2, 3], [4, 5]], 6]))
[1, 2, 3, 4, 5, 6]
>>>  

$ uname -a
Darwin Samys-MacBook-Pro.local 13.3.0 Darwin Kernel Version 13.3.0: Tue Jun  3 21:27:35 PDT 2014; root:xnu-2422.110.17~1/RELEASE_X86_64 x86_64
$ python --version
Python 2.7.5

解决方案 28:

不使用任何库:

def flat(l):
    def _flat(l, r):    
        if type(l) is not list:
            r.append(l)
        else:
            for i in l:
                r = r + flat(i)
        return r
    return _flat(l, [])



# example
test = [[1], [[2]], [3], [['a','b','c'] , [['z','x','y']], ['d','f','g']], 4]    
print flat(test) # prints [1, 2, 3, 'a', 'b', 'c', 'z', 'x', 'y', 'd', 'f', 'g', 4]

解决方案 29:

使用itertools.chain

import itertools
from collections import Iterable

def list_flatten(lst):
    flat_lst = []
    for item in itertools.chain(lst):
        if isinstance(item, Iterable):
            item = list_flatten(item)
            flat_lst.extend(item)
        else:
            flat_lst.append(item)
    return flat_lst

或者不使用链接:

def flatten(q, final):
    if not q:
        return
    if isinstance(q, list):
        if not isinstance(q[0], list):
            final.append(q[0])
        else:
            flatten(q[0], final)
        flatten(q[1:], final)
    else:
        final.append(q)

解决方案 30:

我使用递归来解决任意深度的嵌套列表

def combine_nlist(nlist,init=0,combiner=lambda x,y: x+y):
    '''
    apply function: combiner to a nested list element by element(treated as flatten list)
    '''
    current_value=init
    for each_item in nlist:
        if isinstance(each_item,list):
            current_value =combine_nlist(each_item,current_value,combiner)
        else:
            current_value = combiner(current_value,each_item)
    return current_value

因此,在我定义函数combine_nlist之后,很容易使用这个函数进行扁平化。或者你可以将它组合成一个函数。我喜欢我的解决方案,因为它可以应用于任何嵌套列表。

def flatten_nlist(nlist):
    return combine_nlist(nlist,[],lambda x,y:x+[y])

结果

In [379]: flatten_nlist([1,2,3,[4,5],[6],[[[7],8],9],10])
Out[379]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   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源码管理

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

免费试用