展开列表(不规则)列表
是的,我知道这个主题已经被覆盖了( 在这里 , 这里 , 在 这里 ),但据我所知,所有的解决scheme,除了一个,都失败在这样的列表上:
L = [[[1, 2, 3], [4, 5]], 6]
如果期望的输出是
[1, 2, 3, 4, 5, 6]
或者甚至更好,一个迭代器。 我看到的唯一解决scheme适用于任意嵌套在这个问题中find:
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)
这是最好的模式? 我忽略了什么? 任何问题?
使用生成器函数可以使您的示例更容易阅读,并可能提高性能。
Python 2
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
我在2.6中使用了Iterable ABC 。
Python 3
在Python 3中, basestring
不再多,但是可以使用str
和bytes
的元组来获得相同的效果。
yield from
操作员的收益率一次从一个发电机返回一个项目。 3.3中增加了这个委托给一个子生成器的语法
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
我的解决scheme
def flatten(x): if isinstance(x, collections.Iterable): return [a for i in x for a in flatten(i)] else: return [x]
更简洁一点,但几乎相同。
@ unutbu的非recursion解决scheme的生成器版本,请参阅@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)
生成器使用recursion和鸭子键入(更新为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]
这个flatten
版本避免了python的recursion限制(因此可以与任意深度的嵌套迭代器一起工作)。 这是一个可以处理string和任意迭代(甚至是无限的)的生成器。
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
下面是一些演示其用法的例子:
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
可以处理无限的生成器,但它不能处理无限的嵌套:
def infinitely_nested(): while True: yield IT.chain(infinitely_nested(), IT.repeat(1)) print(list(IT.islice(flatten(infinitely_nested()), 10))) # hangs
这里是recursion平坦函数的处理元组和列表的function版本,并且可以让你抛出任何位置参数的混合。 返回按照arg的顺序生成整个序列的生成器:
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]
这是另一个更有趣的答案
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)
基本上,它将嵌套列表转换为string,使用正则expression式去除嵌套语法,然后将结果转换回(展开)列表。
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
试图创build一个可以使Python中的不规则列表扁平化的函数是很有趣的,但是Python当然是为了使编程更有趣。 下面的生成器可以很好地处理一些注意事项:
def flatten(iterable): try: for item in iterable: yield from flatten(item) except TypeError: yield iterable
它会扁平你可能想要放在一边的数据types(比如bytearray
, bytes
和str
对象)。 另外,代码依赖于从非迭代请求迭代器引发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
testing生成器与提供的列表正常工作。 但是,当新的代码被赋予一个不可迭代的对象时,将会引发一个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 >>>
虽然select了一个优雅和非常pythonic的答案,我会提出我的解决scheme只是为了审查:
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
请告诉我们这个代码有多好还是不好?
我更喜欢简单的答案。 没有发电机。 没有recursion或recursion限制。 刚刚迭代:
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
这适用于两个列表:内循环和外循环。
inner for循环遍历列表。 如果它find一个列表元素,则它(1)使用list.extend()来将该部分扁平化为一层嵌套,并且(2)将keepChecking切换为True。 keepchecking用于控制外部while循环。 如果外部循环设置为true,则触发内部循环进行另一次传递。
这些通行证继续发生,直到找不到更多的嵌套列表。 当一个通行证最终发生在没有被发现的地方时,keepChecking永远不会被触发到true,这意味着listIsNested保持为false并且外部while循环退出。
扁平列表然后返回。
testing运行
flatten([1,2,3,4,[100,200,300,[1000,2000,3000]]])
[1, 2, 3, 4, 100, 200, 300, 1000, 2000, 3000]
以下是2.7.5中的compiler.ast.flatten
实现:
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中已经删除了编译器包。
这是一个简单的函数,可以将任意深度的列表弄平。 没有recursion,以避免堆栈溢出。
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
你可以从第三方包iteration_utilities
使用deepflatten
:
>>> 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]
这是一个迭代器,所以你需要迭代它(例如,通过包装它或在循环中使用它)。 在内部,它使用迭代方法而不是recursion方法,它被写成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
库的作者。
我没有通过所有已经可以得到的答案在这里,但这里是我想出的一个class轮,从lisp的第一个借口和rest表处理
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] >>>
我知道已经有很多很棒的答案,但是我想添加一个使用解决问题的函数式编程方法的答案。 在这个答案我使用双recursion:
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]
完全黑客,但我认为这将工作(取决于你的data_type)
flat_list = ast.literal_eval("[%s]"%re.sub("[\[\]]","",str(the_list)))
这里是另一个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))
它可以忽略任何你想要的特定(或派生)types,它会返回一个迭代器,所以你可以将它转换成任何特定的容器,如列表,元组,字典或简单地使用它,以减less内存占用,好或坏它可以处理初始的非迭代对象,如int …
注意大部分的繁重工作都是用C语言完成的,因为据我所知,itertools是如何实现的,虽然它是recursion的,但是AFAIK并不受pythonrecursion深度限制,因为函数调用是在C中进行的,并不意味着你是由内存限制,特别是在OS X的堆栈大小有今天的硬限制(OS X小牛)…
有一个稍微快一点的方法,但不太可移植的方法,只有使用它,如果你可以假设input的基本元素可以明确确定,否则,你会得到一个无限的recursion,而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))
在这里我们使用集合来检查types,所以它需要O(1)与O(types数量)来检查一个元素是否应该被忽略,当然任何具有派生types的被忽略types的值将会失败,这就是为什么它使用str
, unicode
所以谨慎使用它…
testing:
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
使用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)
我用recursion来解决任何深度的嵌套列表
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之后,很容易用这个函数做扁平化。 或者你可以把它合并成一个function。 我喜欢我的解决scheme,因为它可以应用到任何嵌套列表。
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]
如果你喜欢recursion,这可能是你感兴趣的解决scheme:
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
我实际上是从一些我之前写过的练习计划中改编的。
请享用!
我是python新手,来自lisp背景。 这就是我想出的(查看lulz的var名称):
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]
似乎工作。 testing:
flatten((1,2,3,(4,5,6,(7,8,(((1,2)))))))
收益:
[1, 2, 3, 4, 5, 6, 7, 8, 1, 2]
我没有看到这样的东西,只是从一个关于同一主题的封闭问题到这里,但为什么不只是做这样的事情(如果你知道你想分裂的列表的types):
>>> 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()]
你需要知道元素的types,但是我认为这可以是一般化的,而且在速度方面,我认为它会更快。
不使用任何库:
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]
无耻地从我自己的回答到另一个问题 。
这个function
- 不使用
isinstance
,因为它是邪恶的,打破了鸭子打字。 - 使用recursion递减。 必须有一个答案使用
reduce
。 - 与任意嵌套列表一起使用,嵌套列表的元素可以是嵌套列表,也可以是非嵌套的primefaces列表或primefaces(受recursion限制)。
- 不LBYL。
- 但是不包含包含string作为primefaces的嵌套列表。
代码如下:
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]
我很惊讶没有人想到这一点。 该死的recursion我没有得到这里的高级人员recursion的答案。 无论如何,这是我的尝试。 警告是这是非常具体的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]
最简单的方法是使用variables库使用pip install morph
。
代码是:
import morph list = [[[1, 2, 3], [4, 5]], 6] flattened_list = morph.flatten(list) # returns [1, 2, 3, 4, 5, 6]
我们也可以使用python的'type'function。 当迭代列表时,我们检查项目是否是列表。 如果不是,我们“追加”,否则我们“延长”它。 这里是一个示例代码 –
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, 2, 3, 4, 5, 6, 7, 8]
有关append()和extend()的更多信息,请查看以下网站: https : //docs.python.org/2/tutorial/datastructures.html
这可能是一个老问题,我想在这个问题上采取一些措施。
我是一个愚蠢的家伙,所以我会给一个“愚蠢”的解决scheme。 所有这些recursion都伤害了我的大脑。
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]
我知道这是使用副作用,但是,我最好的理解recursion可以去
这将扁平化一个列表或字典(或列表或词典的字典等)。 它假设这些值是string,并创build一个string,将每个项目与分隔符参数连接起来。 如果你想要,你可以使用分隔符将结果拆分成一个列表对象。 如果下一个值是一个列表或一个string,它使用recursion。 使用key参数来告诉您是否想要字典对象中的键或值(set key为false)。
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=', ')
收益率:
只是,一个,testing,对,尝试,正确的,现在,或者以后,今天,dictionary_test,dictionary_test_two,我的力量是9000