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,
"
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] |
这个版本的
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] |
虽然
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 |
您可以从第三方软件包
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] |
它是一个迭代器,所以您需要对它进行迭代(例如用
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) |
我是
尝试创建一个可以在python中平展不规则列表的函数是很有趣的,当然这就是python的目的(使编程变得有趣)。以下发电机工作正常,但有一些注意事项:
1 2 3 4 5 6 | def flatten(iterable): try: for item in iterable: yield from flatten(item) except TypeError: yield iterable |
它将扁平化您可能希望单独使用的数据类型(如
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 |
使用提供的列表测试发电机工作正常。然而,当一个不可重写的对象被赋予时,新的代码将引发一个
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 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中的
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] |
使用
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(类型数)来检查元素是否应该被忽略,尽管具有所述被忽略类型的派生类型的任何值都将失败,这就是为什么它使用
测验:
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 |
最简单的方法是使用
代码是:
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),因此,如果您输入了太多的函数而没有返回,那么您将填充调用堆栈并有一个看起来像"亲爱的冒险家,我很抱歉,但您的笔记本已满":
这实际上相当简单:"如果你不知道递归的深度,就不要使用递归。"这并不总是正确的,因为在某些情况下,尾调用递归可以优化(TCO)。但在Python中,情况并非如此,即使是"编写良好的"递归函数也不会优化堆栈的使用。关于这个问题,guido有一篇有趣的文章:尾部递归消除。好的。
有一种技术可以让任何递归函数迭代,这种技术我们可以称为自带笔记本。例如,在我们的特定情况下,我们只是在浏览一个列表,进入一个房间就相当于进入一个子列表,您应该问自己的问题是,我如何从一个列表返回到它的父列表?答案并不复杂,重复以下步骤直到
还要注意,这相当于树中的一个df,其中一些节点是
1 2 3 4 5 6 7 | L | ------------------- | | | | 0 --A-- 3 4 | | 1 2 |
DFS遍历的预顺序是:L、0、A、1、2、3、4。记住,为了实现迭代的DFS,您还需要一个堆栈。我之前提出的实施方案导致出现以下状态(对于
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) |
另外,请注意,在
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 |
这将字符串视为"简单项",因此
最后,请记住,不能使用
如果需要测试解决方案,可以使用此函数生成一个简单的嵌套列表:好的。
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 |
给出:
我知道已经有很多很棒的答案,但是我想添加一个使用函数编程方法来解决问题的答案。在这个答案中,我使用了双递归:
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)) |
这里的
不过,如果你知道你的列表中会有方括号,比如
我没有看到任何像这样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]
只使用
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,与将列表转换为字符串的其他答案不同。
黑客,预计会很慢,但我不认为它可以击败可读性。