关于python:展开不规则列表

Flatten an irregular list of lists

是的,我知道这个主题以前已经被讨论过了(这里,这里,这里,这里),但据我所知,所有的解决方案,除了一个,都不能列在这样的列表上:

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

所需输出为

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

或者更棒的是,一个迭代器。在这个问题中,我看到的唯一适用于任意嵌套的解决方案是:

1
2
3
4
5
6
7
8
9
10
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

flatten(L)

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


用generator功能可以让你的小例子easier读到可能的性能提升。 P / < > Python的2

1
2
3
4
5
6
7
def flatten(l):
    for el in l:
        if isinstance(el, collections.Iterable) and not isinstance(el, basestring):
            for sub in flatten(el):
                yield sub
        else:
            yield el

我用的iterable字母添加在2.6。 P / < > Python 3

在Python 3,basestring也没有更多的,但你可以用tuple of strbytes得到有同样的效应。 P / < >

"yield from算子returns an item从generator一美元的时代。这个语法为delegating到subgenerator是添加在3.3 P / < >

1
2
3
4
5
6
def flatten(l):
    for el in l:
        if isinstance(el, collections.Iterable) and not isinstance(el, (str, bytes)):
            yield from flatten(el)
        else:
            yield el


我的解决办法: P / < >

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

更多的小concise漂亮,但多是一样的。 P / < >


generator版本的unutbu @的非recursive级要求的解决方案,通过同步在安得烈的评论: P / < >

1
2
3
4
5
6
7
8
9
10
11
12
13
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

slightly简化版本generator: P / < >

1
2
3
4
5
6
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)


generator用recursion和鸭typing(更新为Python 3): P / < >

1
2
3
4
5
6
7
8
9
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]


这个版本的flattenavoids Python的recursion限制(和因此工程与arbitrarily深,一个嵌套的iterables)。它的generator,能处理的字符串和arbitrary iterables(即使是无限的ones)。 P / < >

1
2
3
4
5
6
7
8
9
10
11
import itertools as IT
import collections

def flatten(iterable, ltypes=collections.Iterable):
    remainder = iter(iterable)
    while True:
        first = next(remainder)
        if isinstance(first, ltypes) and not isinstance(first, basestring):
            remainder = IT.chain(first, remainder)
        else:
            yield first

这里是一些examples demonstrating ITS的使用: P / < >

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
print(list(IT.islice(flatten(IT.repeat(1)),10)))
# [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

print(list(IT.islice(flatten(IT.chain(IT.repeat(2,3),
                                       {10,20,30},
                                       'foo bar'.split(),
                                       IT.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 xrange(ord('a'), ord('z')+1)] + 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能处理generators无限,它不处理无限的nesting: P / < >

1
2
3
4
5
6
def infinitely_nested():
    while True:
        yield IT.chain(infinitely_nested(), IT.repeat(1))

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


我的睾丸功能的版本recursive flatten,把手都tuples和列表,和让你扔在任何组合的positional arguments。returns的generator,产生的整个序列在秩序,由精氨酸精氨酸: P / < >

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

usage: P / < >

1
2
3
4
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]


这里的另一个答案,甚至更多的有趣的…… P / < >

1
2
3
4
5
6
7
8
9
import re

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

    return(d)

basically,它converts的一个嵌套的列表到一个字符串,用途的regex到了带钢的一个嵌套的语法,然后converts的一个结果,回到(flattened)的列表。 P / < >


1
2
3
4
5
6
7
8
9
10
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

您可以从第三方软件包iteration_utilities中使用deepflatten

1
2
3
4
5
6
7
>>> 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方法更快:

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> %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图书馆的作者。


尝试创建一个可以在python中平展不规则列表的函数是很有趣的,当然这就是python的目的(使编程变得有趣)。以下发电机工作正常,但有一些注意事项:

1
2
3
4
5
6
def flatten(iterable):
    try:
        for item in iterable:
            yield from flatten(item)
    except TypeError:
        yield iterable

它将扁平化您可能希望单独使用的数据类型(如bytearraybytesstr对象)。此外,代码依赖于这样一个事实:从非iterable请求迭代器会引发TypeError

1
2
3
4
5
6
7
8
9
10
11
12
>>> 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]
>>>

编辑:

我不同意以前的实现。问题是,你不应该压扁那些不可重复的东西。这很混乱,给人的印象是错误的。

1
2
3
>>> list(flatten(123))
[123]
>>>

下面的生成器几乎与第一个生成器相同,但不存在试图展平不可迭代对象的问题。当给它一个不适当的论据时,它会如人们所期望的那样失败。

1
2
3
4
5
6
def flatten(iterable):
    for item in iterable:
        try:
            yield from flatten(item)
        except TypeError:
            yield item

使用提供的列表测试发电机工作正常。然而,当一个不可重写的对象被赋予时,新的代码将引发一个TypeError。新行为的示例如下所示。

1
2
3
4
5
6
7
8
9
10
11
>>> 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
>>>

虽然一个elegant和非常pythonic答案已选择的我目前的解决方案只是为我的评论: P / < >

1
2
3
4
5
6
7
8
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

请告诉我这好的或坏的代码吗? P / < >


我prefer简单的回答。没有generators。没有recursion或recursion的限制。只是iteration: P / < >

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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

这个厂与两个列表:一个内环路和外环路,而为一。 P / < >

同步环内为iterates通过列表。如果它finds元的列表,它(1)用途的list.extend(到),flatten海岸的一个水平的nesting和(2)switches keepchecking到真实的。keepchecking也曾经控制的外环,而。如果外环套获取到真实的,它triggers环内的另一通。 P / < >

那些passes继续发生,直到没有更多的发现是一个嵌套的列表。当通过最后occurs哪里是没有发现,keepchecking从来没有得到tripped到真正的,这意味着listisnested停止,风格和虚假的外环,而exits。 P / < >

"flattened列表,然后returned。 P / < >

身体的运行 P / < >

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

[1, 2, 3, 4, 100, 200, 300, 1000, 2000, 3000] P / < >


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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


下面是2.7.5中的compiler.ast.flatten实现:

1
2
3
4
5
6
7
8
9
10
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

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

还要注意:

Deprecated since version 2.6: The compiler package has been removed in Python 3.


我并没有把所有已经有的答案都读一遍,但我想出了一个单行程序,借用了Lisp的第一和剩余列表处理方法。

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

这里有一个简单的和一个不那么简单的例子-

1
2
3
4
5
6
>>> 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]
>>>


我很惊讶没人想到这一点。该死的递归,我不知道这里的高级人员给出的递归答案。不管怎样,这是我的尝试。需要注意的是,它非常特定于OP的用例

1
2
3
4
5
6
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
[1, 2, 3, 4, 5, 6]

使用itertools.chain

1
2
3
4
5
6
7
8
9
10
11
12
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

或者没有链子:

1
2
3
4
5
6
7
8
9
10
11
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)

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

1
2
3
4
5
6
7
8
9
10
11
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

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

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

结果

1
2
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]


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

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

这是另一个PY2方法,我不确定它是最快的,还是最优雅的,还是最安全的…

1
2
3
4
5
6
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))

它可以忽略您想要的任何特定(或派生)类型,它返回一个迭代器,因此您可以将它转换为任何特定的容器,如list、tuple、dict或简单地使用它来减少内存占用,无论是好是坏,它都可以处理初始的不可重复对象,如int…

注意,大部分繁重的工作都是在C中完成的,因为据我所知,ITertools是如何实现的,所以虽然它是递归的,但是afaik它不受python递归深度的限制,因为函数调用是在C中进行的,尽管这并不意味着您受到内存的限制,特别是在OS X中,到今天为止它的堆栈大小有一个硬限制(OSX小牛队……

有一个稍微快一点的方法,但是不太可移植的方法,只有当你可以假设输入的基本元素可以显式地确定,否则,你将得到一个无限的递归,并且OSX的堆栈大小有限,会很快抛出一个分段错误…

1
2
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,所以要小心使用它…

测验:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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

最简单的方法是使用pip install morph使用变形库。

代码是:

1
2
3
4
import morph

list = [[[1, 2, 3], [4, 5]], 6]
flattened_list = morph.flatten(list)  # returns [1, 2, 3, 4, 5, 6]

这是一个在python2上展平的简单实现

1
2
3
4
5
6
flatten=lambda l: reduce(lambda x,y:x+y,map(flatten,l),[]) if isinstance(l,list) else [l]

test=[[1,2,3,[3,4,5],[6,7,[8,9,[10,[11,[12,13,14]]]]]],]
print flatten(test)

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

当试图回答这样一个问题时,你真的需要给出作为解决方案的代码的局限性。如果仅仅是关于性能的话,我不会介意太多,但是大多数作为解决方案(包括公认的答案)提出的代码都无法将深度超过1000的列表变平。好的。

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

如果您不太熟悉调用堆栈,那么下面的内容可能会有所帮助(否则您只需滚动到实现)。好的。调用堆栈大小和递归编程(地牢模拟)找到宝藏然后离开

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

  • 很难(很长时间)找到宝藏,因为你必须解开(可能很难)谜语才能到达那里。
  • 一旦找到宝藏,回到入口可能很容易,你只需要在另一个方向上使用相同的路径(尽管这需要一些记忆来回忆你的路径)。
  • 当进入地牢时,你注意到这里有一个小笔记本。在解决了一个谜语后(当你进入一个新房间时),你决定用它来写下你离开的每个房间,这样你就可以回到入口了。这是一个天才的想法,你甚至不会花一分钱来实施你的战略。好的。

    你进入地牢,成功地解决了前1001个谜语,但这里有一些你没有计划的事情,你在你借来的笔记本里没有剩余的空间。你决定放弃你的任务,因为你更喜欢没有宝藏,而不是永远迷失在地牢里(这看起来确实很聪明)。好的。执行递归程序

    基本上,这和找到宝藏是一样的。地牢是计算机的内存,你现在的目标不是找到宝藏,而是计算一些函数(为给定的x找到f(x))。这些指示只是帮助您解决f(x)问题的子程序。您的策略与调用堆栈策略相同,笔记本是堆栈,房间是函数的返回地址:好的。

    1
    2
    3
    4
    5
    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个函数。同样重要的是要理解,一旦从函数返回,调用堆栈就从所使用的地址中释放出来(因此,名称"stack",返回地址在进入函数之前被推入,在返回时被拉出)。在一个简单递归的特殊情况下(函数f,调用它自己一次--一次又一次--),您将反复输入f,直到计算完成(直到找到宝藏),然后从f返回,直到回到您最初调用f的地方。调用堆栈将永远不会从任何内容中释放,直到最后从所有返回地址中逐个释放。好的。如何避免这个问题?

    这实际上相当简单:"如果你不知道递归的深度,就不要使用递归。"这并不总是正确的,因为在某些情况下,尾调用递归可以优化(TCO)。但在Python中,情况并非如此,即使是"编写良好的"递归函数也不会优化堆栈的使用。关于这个问题,guido有一篇有趣的文章:尾部递归消除。好的。

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

  • 当输入一个新的子列表(注意,一个列表地址+索引也是一个地址,因此我们只使用调用堆栈使用的完全相同的技术)时,将当前列表addressindex推到stack中;
  • 每次找到一个项目时,都会将其添加(或将其添加到列表中);
  • 一旦列表被完全浏览,使用stack返回addressindex返回父列表。
  • 还要注意,这相当于树中的一个df,其中一些节点是A = [1, 2]的子列表,一些是简单的项:0, 1, 2, 3, 4(对于L = [0, [1,2], 3, 4])。树看起来像这样:好的。

    1
    2
    3
    4
    5
    6
    7
                        L
                        |
               -------------------
               |     |     |     |
               0   --A--   3     4
                   |   |
                   1   2

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

    1
    2
    3
    4
    5
    6
    7
    8
    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中,可以使用迭代器而不是简单的列表来简化一点。对(子)迭代器的引用将用于存储子列表返回地址(而不是同时具有列表地址和索引)。这不是很大的区别,但我觉得这更易读(而且速度更快):好的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    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_like中,我有isinstance(item, list),可以更改它来处理更多的输入类型,这里我只想得到最简单的版本,其中(iterable)只是一个列表。但你也可以这样做:好的。

    1
    2
    3
    4
    5
    6
    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),让我们假设这是一个练习,让读者更清楚。好的。其他实施的测试和备注

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    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]]]]]。好的。好啊。


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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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
    [1, 2, 3, 4, 5, 6, 7]


    我不确定这是否需要更快或更有效,但这是我要做的:

    1
    2
    3
    4
    5
    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]"],你就必须做些别的事情。


    我没有看到任何像这样posted在这里和这里有只从一个封闭的问题上同样的主题,但为什么不只是做一些像这样的(如果你知道类型的名单,你想分裂): P / < >

    1
    2
    3
    >>> 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()]

    你会需要知道类型的元素,但我认为这可以generalised和在词汇表中的速度(我认为它会更快。 P / < >


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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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)

    From my own code at https://github.com/jorgeorpinel/flatten_nested_lists/blob/master/flatten.py


    如果你喜欢recursion,这可能在溶液中的利息给你: P / < >

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    def f(E):
        if E==[]:
            return []
        elif type(E) != list:
            return [E]
        else:
            a = f(E[0])
            b = f(E[1:])
            a.extend(b)
            return a

    但是我adapted这从一些实践方案的代码,我让我写的,而回。 P / < >

    喜欢! P / < >


    我是新到的来自Python和Lisp的背景。这就是我来到了(看看的变种名称为lulz): P / < >

    1
    2
    3
    4
    5
    6
    7
    8
    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]

    似乎工作。身体: P / < >

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

    returns: P / < >

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

    从我以前的回答来看,这个函数可以使我能想到的大多数情况变平。我相信这可以归结为python2.3。

    1
    2
    3
    4
    5
    6
    7
    def flatten(item, keepcls=(), keepobj=()):
        if not hasattr(item, '__iter__') or isinstance(item, keepcls) or item in keepobj:
            yield item
        else:
            for i in item:
                for j in flatten(i, keepcls, keepobj + (item,)):
                    yield j

    循环表

    1
    2
    >>> list(flatten([1, 2, [...], 3]))
    [1, 2, [1, 2, [...], 3], 3]

    深度优先列表

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

    嵌套重复列表:

    1
    2
    >>> list(flatten([[1,2],[1,[1,2]],[1,2]]))
    [1, 2, 1, 1, 2, 1, 2]

    带听写的列表(或其他不平展的对象)

    1
    2
    >>> list(flatten([1,2, {'a':1, 'b':2}, 'text'], keepcls=(dict, str)))
    [1, 2, {'a': 1, 'b': 2}, 'text']

    任何迭代

    1
    2
    >>> list(flatten((x for x in [1,2, set([3,(4,5),6])])))
    [1, 2, 4, 5, 3, 6]

    You may want to keep some default classes in keepcls to make calling
    the function more terse.


    不使用任何库:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    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]

    用python 3迭代求解

    此解决方案可以用于除str和bytes之外的所有对象。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    from collections import Iterable
    from collections import Iterator


    def flat_iter(obj):
        stack = [obj]
        while stack:
            element = stack.pop()
            if element and isinstance(element, Iterator):
                stack.append(element)
                try:
                    stack.append(next(element))
                except StopIteration:
                    stack.pop()
            elif isinstance(element, Iterable) and not isinstance(element, (str, bytes)):
                stack.append(iter(element))
            else:
                yield element


    tree_list = [[(1,2,3),(4,5,6, (7,8, 'next element is 5')), (5,6), [[[3,4,5],'foo1'],'foo2'],'foo3']]

    not_iterable = 10

    it1 = flat_iter(tree_list)
    it2 = flat_iter(not_iterable)

    print(list(it1))
    print(list(it2))

    [1, 2, 3, 4, 5, 6, 7, 8, 'next element is 5', 5, 6, 3, 4, 5, 'foo1', 'foo2', 'foo3']

    [10]


    只使用funcy库:pip install funcy

    1
    2
    3
    4
    5
    import funcy


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

    Python 3

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    from collections import Iterable

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

    def flatten(thing):
        result = []

        if isinstance(thing, Iterable):
            for item in thing:
                result.extend(flatten(item))
        else:
            result.append(thing)

        return result


    flat = flatten(L)
    print(flat)


    这将使列表或字典(或列表或字典列表等)变平。它假定值是字符串,并创建一个字符串,用分隔符参数连接每个项。如果需要,可以使用分隔符将结果拆分为一个列表对象。如果下一个值是列表或字符串,则使用递归。使用key参数来判断是否需要字典对象中的键或值(将key设置为false)。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    def flatten_obj(n_obj, key=True, my_sep=''):
        my_string = ''
        if type(n_obj) == list:
            for val in n_obj:
                my_sep_setter = my_sep if my_string != '' else ''
                if type(val) == list or type(val) == dict:
                    my_string += my_sep_setter + flatten_obj(val, key, my_sep)
                else:
                    my_string += my_sep_setter + val
        elif type(n_obj) == dict:
            for k, v in n_obj.items():
                my_sep_setter = my_sep if my_string != '' else ''
                d_val = k if key else v
                if type(v) == list or type(v) == dict:
                    my_string += my_sep_setter + flatten_obj(v, key, my_sep)
                else:
                    my_string += my_sep_setter + d_val
        elif type(n_obj) == str:
            my_sep_setter = my_sep if my_string != '' else ''
            my_string += my_sep_setter + n_obj
            return my_string
        return my_string

    print(flatten_obj(['just', 'a', ['test', 'to', 'try'], 'right', 'now', ['or', 'later', 'today'],
                    [{'dictionary_test': 'test'}, {'dictionary_test_two': 'later_today'}, 'my power is 9000']], my_sep=', ')

    产量:

    我的能力是9000


    这可能是个老问题,我想试试看。

    我是个哑巴,所以我会给出一个"哑巴"的解决方案。所有的递归都会伤害我的大脑。

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

    def flatten(nested_list, container):
        for item in nested_list:
            if isintance(item, list):
                flatten(item)
            else:
                container.append(i)

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

    我知道它在使用副作用,但我对递归的理解是这样的


    我们还可以使用python的"type"函数。在迭代列表时,我们检查该项是否是列表。如果没有,我们就"附加"它,否则我们就"扩展"它。这是一个示例代码-

    1
    2
    3
    4
    5
    6
    7
    8
    l=[1,2,[3,4],5,[6,7,8]]
    x=[]
    for i in l:
        if type(i) is list:
            x.extend(i)
        else:
            x.append(i)
    print x

    输出:

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

    有关append()和extend()的详细信息,请访问以下网站:https://docs.python.org/2/tutorial/datastructures.html网站


    不知羞耻地从我自己对另一个问题的回答中走出来。

    这个函数

    • 不使用isinstance,因为它是邪恶的,会破坏鸭子的打字。
    • 递归使用reduce。必须有一个使用reduce的答案。
    • 使用任意嵌套列表,其元素要么是嵌套列表,要么是非嵌套原子列表,要么是原子(受递归限制)。
    • 不是LBYL。
    • 但不能使用嵌套列表,该列表包含作为原子的字符串。

    代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    def flattener(left, right):
        try:
            res = reduce(flattener, right, left)
        except TypeError:
            left.append(right)
            res = left
        return res


    def flatten(seq):
        return reduce(flattener, seq, [])


    >>> nested_list = [0, [1], [[[[2]]]],
                       [3, [], [4, 5]],
                       [6, [7, 8],
                        9, [[[]], 10,
                            []]],
                       11, [], [],
                       [12]]
    >>> flatten(nested_list)
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

    类似于迪利加的回答

    1
    2
    weird_list=[[1, 2, 3], [4, 5, 6], [7], [8, 9]]
    nice_list = list(map(int, ''.join([e for e in str(weird_list) if e not in '[ ]']).split(',')))

    不使用实例的简单函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    L = [[[1, 2, 3], [4, 5]], 6]
    l1 = []
    def FlattenList(List1):
        for i in range(len(List1)):
            if type(List1[i]) == type([]):
                FlattenList(List1[i])
            else:
                l1.append(List1[i])
        return l1


    FlattenList(L)
    [1, 2, 3, 4, 5, 6]

    1
    2
    L2 = [o for k in [[j] if not isinstance(j,list) else j for j in [k for i in [[m] if not
    isinstance(m,list) else m for m in L] for k in i]] for o in k]


    1
    2
    def flatten(nestedList):
        return eval('['+str(nestedList).replace('[','').replace(']','')+']')

    将嵌套列表转换为字符串,移除括号,然后在其周围仅添加两个括号并计算。

    如果所有叶元素都是整数,则将工作。

    如果叶元素是任意字符串(可能包含括号),则不起作用。

    需要根据是否适用于其他情况,对每个案例进行评估。

    不使用regex,与将列表转换为字符串的其他答案不同。

    黑客,预计会很慢,但我不认为它可以击败可读性。