是的,我知道此主题已经涵盖在之前(here,here,here,here),但就我所知,所有解决方案,除了例如,在这样的列表上失败:
L = [[[1, 2, 3], [4, 5]], 6]
所需输出
的位置[1, 2, 3, 4, 5, 6]
或者甚至更好,一个迭代器。我看到的唯一适用于任意嵌套的解决方案是in this question:
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)
这是最好的型号吗?我忽略了什么吗?有什么问题吗?
答案 0 :(得分:343)
使用生成器函数可以使您的示例更容易阅读,并可能提高性能。
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中,basestring
已不复存在,但您可以使用str
和bytes
元组来获得相同的效果。
yield from
运算符一次从一个生成器返回一个项目。这个syntax for delegating to a subgenerator已添加到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
答案 1 :(得分:47)
我的解决方案:
import collections
def flatten(x):
if isinstance(x, collections.Iterable):
return [a for i in x for a in flatten(i)]
else:
return [x]
更简洁,但几乎相同。
答案 2 :(得分:34)
@ 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)
答案 3 :(得分:33)
使用递归和鸭子输入的生成器(针对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 :(得分:26)
这个版本的flatten
避免了python的递归限制(因此适用于任意深度,嵌套的迭代)。它是一个可以处理字符串和任意迭代(甚至是无限迭代)的生成器。
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, (str, bytes)):
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 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 IT.chain(infinitely_nested(), IT.repeat(1))
print(list(IT.islice(flatten(infinitely_nested()), 10)))
# hangs
答案 5 :(得分:23)
这是我的递归flatten的功能版本,它处理元组和列表,并允许你输入任何位置参数的混合。返回一个生成整个序列的生成器,arg by 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]
答案 6 :(得分:13)
这是另一个更有趣的答案......
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)
基本上,它将嵌套列表转换为字符串,使用正则表达式去除嵌套语法,然后将结果转换回(展平)列表。
答案 7 :(得分: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
答案 8 :(得分:7)
您可以使用第三方软件包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
库的作者。
答案 9 :(得分:6)
尝试创建一个可以在Python中压缩不规则列表的函数很有趣,但当然这就是Python的目的(使编程变得有趣)。下面的生成器可以很好地解决一些注意事项:
def flatten(iterable):
try:
for item in iterable:
yield from flatten(item)
except TypeError:
yield iterable
它会压缩您可能希望保留的数据类型(例如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
使用提供的列表测试生成器工作正常。但是,当给出不可迭代的对象时,新代码将引发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
>>>
答案 10 :(得分:5)
虽然选择了一个优雅且非常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
请说明这段代码有多好或多坏?
答案 11 :(得分:4)
我更喜欢简单的答案。没有发电机。没有递归或递归限制。只是迭代:
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]
答案 12 :(得分:4)
这是一个简单的函数,可以平滑任意深度的列表。没有递归,以避免堆栈溢出。
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 :(得分:2)
我很惊讶没人想到这个。该死的递归我没有得到高级人员在这里提出的递归答案。无论如何,这是我对此的尝试。需要注意的是OP的用例
非常具体<div id="test"><div>
输出:
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)
答案 14 :(得分:2)
我没有在这里查看所有已经提供的答案,但这里是我提出的一个内容,借用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]
>>>
答案 15 :(得分:2)
这是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中已删除了编译器包。
答案 16 :(得分:1)
当试图回答这样一个问题时,您确实需要给出您提议作为解决方案的代码的限制。如果只考虑性能,我不会太在意,但是提议作为解决方案的大多数代码(包括公认的答案)都无法使深度大于1000的列表变平。
当我说大多数代码时,我的意思是所有使用任何形式的递归的代码(或调用递归的标准库函数)。所有这些代码都会失败,因为对于每个递归调用,(调用)堆栈都增加一个单位,而(默认)python调用堆栈的大小为1000。
如果您不太熟悉调用堆栈,那么以下内容可能会有所帮助(否则,您可以滚动至实施)。
想象一下,您进入一个带有编号房间的巨大地牢,寻找宝藏。您不知道地点,但是您有关于找到宝藏的一些指示。每个指示都是一个谜(难度各不相同,但是您无法预测它们的难易程度)。您决定对节省时间的策略进行一点思考,然后进行两个观察:
进入地牢时,您会在这里看到一本小的笔记本。您决定使用它来写下谜题(进入新房间时)后退出的每个房间,这样您就可以返回到入口。那是个天才的主意,您甚至不会花一分钱来实施自己的策略。
您进入地牢,成功地解决了第一个1001个谜题,但是这是您未计划的事情,您借用的笔记本电脑中没有剩余空间。您决定放弃您的任务,因为您更喜欢没有财宝而不是在地牢中永远失去(确实看起来很聪明)。
基本上,这与寻找宝藏完全相同。地牢是计算机的内存,您现在的目标不是寻找宝藏,而是计算某些功能(找到 f(x)给定 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
的地方。调用栈将永远不会释放任何东西,直到最后将所有返回地址都释放出来为止。
这实际上非常简单:“如果您不知道递归的深度,请不要使用递归”。在某些情况下,Tail Call recursion can be Optimized (TCO)并非总是如此。但是在python中,情况并非如此,即使“写得好”的递归函数也会不优化堆栈使用。 Guido上有一个有趣的帖子,关于这个问题:Tail Recursion Elimination。
您可以使用一种技术来迭代任何递归函数,这种技术可以称为 自带笔记本 。例如,在我们的特定情况下,我们只是在探索一个列表,进入一个房间等同于进入一个子列表,您应该问自己的问题是我如何才能从列表回到父列表?答案并不那么复杂,请重复以下步骤,直到stack
为空:
address
和index
推入stack
中(请注意,列表地址+索引也是地址,因此我们只使用完全相同的地址调用堆栈使用的技术); yield
(或将它们添加到列表中); 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,您还需要“堆栈”。我之前提出的实现导致具有以下状态(对于stack
和flat_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_like
中,我有isinstance(item, list)
,可以将其更改为处理更多输入类型,在这里,我只想拥有最简单的版本,(可迭代)只是一个列表。但是您也可以这样做:
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)
,因为在内部它将使用对__repr__
(RecursionError: maximum recursion depth exceeded while getting the repr of an object
)的递归调用。出于相同的原因,涉及flatten
的{{1}}的解决方案将因相同的错误消息而失败。
如果需要测试解决方案,则可以使用此功能来生成一个简单的嵌套列表:
str
哪个给出: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)
。
答案 17 :(得分:1)
我不确定这是否更快或更有效,但这就是我所做的:
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]"]
,你就必须做其他事情。
答案 18 :(得分:1)
我知道已经有很多很棒的答案,但我想添加一个使用解决问题的函数式编程方法的答案。在这个答案中,我使用了双递归:
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]
答案 19 :(得分:1)
这是在python2上进行flatten的简单实现
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]
答案 20 :(得分:1)
只需使用funcy
库:
resource_size(&mem_res);
pip install funcy
答案 21 :(得分:1)
最简单的方法是使用pip install morph
使用morph库。
代码是:
import morph
list = [[[1, 2, 3], [4, 5]], 6]
flattened_list = morph.flatten(list) # returns [1, 2, 3, 4, 5, 6]
答案 22 :(得分:1)
使用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)
答案 23 :(得分:1)
我使用递归来解决任何深度的 嵌套列表
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]
答案 24 :(得分:1)
这是另一种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))
它可以忽略你想要的任何特定(或派生)类型,它返回一个迭代器,所以你可以将它转换为任何特定的容器,如list,tuple,dict,或者只是消耗它以减少内存占用,无论好坏,它都可以处理初始的非可迭代对象,例如int ...
注意大多数繁重工作都是用C语言完成的,因为据我所知,迭代工具是如何实现的,所以虽然它是递归的,但是由于函数调用正在发生,因此它不受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)vs O(类型数)来检查是否应该忽略一个元素,当然任何带有所述被忽略的派生类型的值类型会失败,这就是为什么它使用str
,unicode
所以谨慎使用它...
测试:
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
答案 25 :(得分:1)
完全hacky,但我认为它会起作用(取决于你的data_type)
flat_list = ast.literal_eval("[%s]"%re.sub("[\[\]]","",str(the_list)))
答案 26 :(得分:0)
此方案基于python的iteration-utilities
library及其函数 deepflatten
from iteration_utilities import deepflatten
list(deepflatten(test))
答案 27 :(得分:0)
无耻地从我对another question的回答中获取。
此功能
isinstance
,因为它是邪恶的并打破了鸭子打字。reduce
。必须使用reduce
答案。以下代码:
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]
答案 28 :(得分:0)
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]
答案 29 :(得分:0)
大多数答案都使用循环遍历所有项目。在这里,我有一个使用EAFP方法进行操作的变体:尝试在输入中获取一个迭代器,如果成功,则首先在第一个元素上运行函数,然后在其余的迭代器上运行函数。如果您无法获得迭代器,或者它是字符串或字节对象,则产生元素。
由于A. Kareem的建议,他发现我的代码非常慢,这是因为递归对于字符串和字节对象花费的时间太长,这是我代码的改进版本。
def flatten(x, it = None):
try:
if type(x) in (str, bytes):
yield x
else:
if not it:
it = iter(x)
yield from flatten(next(it))
if type(x) not in (str, bytes):
yield from flatten(x, it)
except StopIteration:
pass
except Exception:
yield x
oldlist = [1,[[[["test",3]]]],((4,5,6)),[ bytes("test", encoding="utf-8"),7,[8,9]]]
newlist = [ x for x in flatten(oldlist) ]
print(newlist)
# [1, 'test', 3, 4, 5, 6, b'test', 7, 8, 9]
答案 30 :(得分:0)
我修改了接受答案的代码,并添加了仅展平至指定深度的选项。 max_depth = 0表示列表保持原样。也许有人可以使用它:
def flatten(l, __depth=0, max_depth=100):
for el in l:
if isinstance(el, collections.Iterable) and not isinstance(el, (str, bytes)):
__depth += 1
if __depth <= max_depth:
yield from flatten(el, __depth=__depth, max_depth=max_depth)
else:
yield el
__depth -= 1
else:
yield el
一些例子:
# A
l = []
depth = 5
for i in range(depth):
el = i
for j in range(i):
el = [el]
l.append(el)
# [0, [1], [[2]], [[[3]]], [[[[4]]]]]
for i in range(depth):
print(list(flatten_gen(l, max_depth=i)))
# [0, [1], [[2]], [[[3]]], [[[[4]]]]]
# [0, 1, [2], [[3]], [[[4]]]]
# [0, 1, 2, [3], [[4]]]
# [0, 1, 2, 3, [4]]
# [0, 1, 2, 3, 4]
# B
l = [[1, 2], [3, 4, [5, 6, [7, [8, [9]]], 10], 12, [13]], 14, [15]]
for i in range(6):
print(list(flatten_gen(l, max_depth=i)))
# [[1, 2], [3, 4, [5, 6, [7, [8, [9]]], 10], 12, [13]], 14, [15]]
# [ 1, 2, 3, 4, [5, 6, [7, [8, [9]]], 10], 12, [13], 14, 15]
# [ 1, 2, 3, 4, 5, 6, [7, [8, [9]]], 10, 12, 13, 14, 15]
# [ 1, 2, 3, 4, 5, 6, 7, [8, [9]], 10, 12, 13, 14, 15]
# [ 1, 2, 3, 4, 5, 6, 7, 8, [9], 10, 12, 13, 14, 15]
# [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15]
答案 31 :(得分:0)
def nested_list(depth):
l = [depth]
for i in range(depth-1, 0, -1):
l = [i, l]
return l
nested_list(10)
[1,[2,[3,[4,[5,[6,[7,[8,[9,[10]]]]]]]]]]]]] p
def Flatten(ul):
fl = []
for i in ul:
if type(i) is list:
fl += Flatten(i)
else:
fl += [i]
return fl
Flatten(nested_list(10))
[1、2、3、4、5、6、7、8、9、10]
基准化
l = nested_list(100)
https://stackoverflow.com/a/2158532
import collections 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
%%timeit -n 1000
list(flatten(l))
每个循环320 µs±14.3 µs(平均±标准偏差,共运行7次,每个循环1000次)
%%timeit -n 1000
Flatten(l)
每个循环60 µs±10.2 µs(平均±标准偏差,共运行7次,每个循环1000次)
list(flatten(l)) == Flatten(l)
是
答案 32 :(得分:0)
如果您喜欢递归,这可能是您感兴趣的解决方案:
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
我实际上是根据我之前写过的一些练习程序代码改编的。
享受!
答案 33 :(得分:0)
没有递归或嵌套循环。几行。格式正确且易于阅读:
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代码
答案 34 :(得分:0)
我是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]
似乎工作。测试:
flatten((1,2,3,(4,5,6,(7,8,(((1,2)))))))
返回:
[1, 2, 3, 4, 5, 6, 7, 8, 1, 2]
答案 35 :(得分:0)
我没有看到这样的内容发布在这里,只是从一个关于同一主题的封闭问题来到这里,但为什么不做这样的事情(如果你知道要拆分的列表的类型):
>>> 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()]
您需要知道元素的类型,但我认为这可以推广,而且就速度而言,我认为它会更快。
答案 36 :(得分:0)
从我的previous answer开始,这个功能可以解决我能想到的大多数情况。我相信这可以解决python 2.3。
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
循环列表
>>> list(flatten([1, 2, [...], 3]))
[1, 2, [1, 2, [...], 3], 3]
深度优先列出
>>> list(flatten([[[1, 2, 3], [4, 5]], 6]))
[1, 2, 3, 4, 5, 6]
嵌套重复列表:
>>> list(flatten([[1,2],[1,[1,2]],[1,2]]))
[1, 2, 1, 1, 2, 1, 2]
带有dicts的列表(或其他未展平的对象)
>>> list(flatten([1,2, {'a':1, 'b':2}, 'text'], keepcls=(dict, str)))
[1, 2, {'a': 1, 'b': 2}, 'text']
任何迭代
>>> list(flatten((x for x in [1,2, set([3,(4,5),6])])))
[1, 2, 4, 5, 3, 6]
您可能希望在
keepcls
中保留一些默认类来进行调用 功能更简洁。
答案 37 :(得分:0)
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(',')))
答案 38 :(得分:0)
此解决方案可以使用除str和bytes之外的所有对象。
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,&#39;下一个元素是5&#39;,5,6,3,4,5,&#39; foo1&#39; ,&#39; foo2&#39;,&#39; foo3&#39;]
[10]
答案 39 :(得分:0)
<强>的Python-3 强>
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)
答案 40 :(得分:0)
这将使列表或字典(或列表或词典列表等)变平。它假定值是字符串,并创建一个字符串,使用separator参数连接每个项目。如果您愿意,可以使用分隔符将结果拆分为列表对象。如果下一个值是列表或字符串,它使用递归。使用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=', ')
的产率:
just, a, test, to, try, right, now, or, later, today, dictionary_test, dictionary_test_two, my power is 9000
答案 41 :(得分:0)
我是个笨蛋,所以我会给出一个“愚蠢”的解决方案。所有的递归都会伤害我的大脑。
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]
我知道它正在使用副作用,但是这是我对递归的最好理解可以去
答案 42 :(得分:0)
我们也可以使用&#39;类型&#39; python的功能。迭代列表时,我们检查项目是否是列表。如果不是,我们会追加&#39;否则我们会扩展&#39;它。这是一个示例代码 -
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
答案 43 :(得分:0)
不使用任何库:
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]
答案 44 :(得分:-1)
简单函数不使用实例
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]
答案 45 :(得分:-1)
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]
答案 46 :(得分:-1)
认为以下内容可能会在python 3中起作用:
def get_flat_iter(xparent):
try:
r = xparent
if hasattr(xx, '__iter__'):
iparent = iter(xparent)
if iparent != xparent:
r = map(a, xparent)
finally:
pass
return r
irregular_list = [1, [2, [3, 4]]]
flat_list = list(irregular_list)
print(flat_list) # [1, 2, 3, 4]
答案 47 :(得分:-1)
def flatten(item) -> list:
if not isinstance(item, list): return item
return reduce(lambda x, y: x + [y] if not isinstance(y, list) else x + [*flatten(y)], item, [])
两行归约功能。