是的,我知道这个主题之前已经被讨论过了:

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

这是最好的方法吗?我是不是忽略了什么?任何问题吗?


当前回答

这是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]

其他回答

我修改了接受的答案的代码,并添加了关键字max_depth,以只将其压平到指定的深度。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]

无耻地从我自己对另一个问题的回答中提取。

这个函数

不使用isinstance,因为它是邪恶的,破坏了鸭子的输入。 递归使用reduce。肯定有一个用reduce的答案。 适用于任意嵌套列表,其元素要么是嵌套列表,要么是非嵌套原子列表,要么是原子(受递归限制)。 不是LBYL。 但对于包含字符串作为原子的嵌套列表则不是这样。

下面的代码:

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]

我在这里没有看到类似的帖子,只是从一个关于同一主题的封闭问题中得到的,但为什么不做这样的事情呢(如果你知道你想拆分的列表类型):

>>> 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()]

你需要知道元素的类型,但我认为这是可以推广的,就速度而言,我认为它会更快。

这将扁平化一个列表或字典(或列表的列表或字典的字典等)。它假设值是字符串,并创建一个字符串,将每个项与分隔符参数连接起来。如果需要,可以使用分隔符将结果拆分为列表对象。如果下一个值是列表或字符串,则使用递归。使用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

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

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之后,很容易使用这个函数来做flatting。或者你可以把它组合成一个函数。我喜欢我的解决方案,因为它可以应用于任何嵌套列表。

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]