是的,我知道这个主题之前已经被讨论过了:
Python成语链(扁平化)有限迭代对象的无限迭代?
在Python中扁平化一个浅列表
理解平展一个序列的序列吗?
我如何从列表的列表中创建一个平面列表?
但据我所知,所有的解决方案,除了一个,在像[[[1,2,3],[4,5]],6]这样的列表上失败,其中期望的输出是[1,2,3,4,5,6](或者更好,一个迭代器)。
我看到的唯一解决方案,适用于任意嵌套是在这个问题:
def flatten(x):
result = []
for el in x:
if hasattr(el, "__iter__") and not isinstance(el, basestring):
result.extend(flatten(el))
else:
result.append(el)
return result
这是最好的方法吗?我是不是忽略了什么?任何问题吗?
我很惊讶居然没人想到这一点。该死的递归,我没有得到这里的高级人员给出的递归答案。总之,这是我的尝试。警告是它非常特定于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]
我更喜欢简单的答案。没有发电机。没有递归或递归限制。迭代:
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]
这将扁平化一个列表或字典(或列表的列表或字典的字典等)。它假设值是字符串,并创建一个字符串,将每个项与分隔符参数连接起来。如果需要,可以使用分隔符将结果拆分为列表对象。如果下一个值是列表或字符串,则使用递归。使用key参数来告诉您是否需要字典对象中的键或值(将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
用Python 3迭代解决
此解决方案可用于除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,下一个元素是5,5,6,3,4,5,‘foo1’,‘foo2’,‘foo3’)
[10]
我很惊讶居然没人想到这一点。该死的递归,我没有得到这里的高级人员给出的递归答案。总之,这是我的尝试。警告是它非常特定于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]