如何在Python中将嵌套列表转换为一维列表?

30

我尝试过我所知道的一切方法,包括分割数组并将它们重新组合以及甚至使用itertools:

import itertools

def oneDArray(x):
    return list(itertools.chain(*x))

我想要的结果:

a) print oneDArray([1,[2,2,2],4]) == [1,2,2,2,4]

奇怪的是,对于

b) print oneDArray([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) == [1, 2, 3, 4, 5, 6, 7, 8, 9]

问题1)如何使部分a按照我的意愿工作(有什么提示吗?)

问题2)为什么上述代码对于部分b起作用而对部分a不起作用?


1
我在SO上找不到我想要的答案,因为我的搜索结果中没有任何关于“flatten”的内容,但这里给出的答案帮助我澄清了很多问题! - compski
15个回答

28

您需要递归循环遍历列表,并检查该项是否可迭代(字符串也是可迭代的,但要跳过它们)。

itertools.chain 对于 [1,[2,2,2],4] 不起作用,因为它要求所有项都可迭代,但是 14(整数)不可迭代。 这就是为什么它对第二个列表有效,因为它是一个包含其他列表的列表。

>>> from collections import Iterable
def flatten(lis):
     for item in lis:
         if isinstance(item, Iterable) and not isinstance(item, str):
             for x in flatten(item):
                 yield x
         else:        
             yield item

>>> lis = [1,[2,2,2],4]
>>> list(flatten(lis))
[1, 2, 2, 2, 4]
>>> list(flatten([[1, 2, 3], [4, 5, 6], [7, 8, 9]]))
[1, 2, 3, 4, 5, 6, 7, 8, 9]

适用于任何嵌套级别:

>>> a = [1,[2,2,[2]],4]
>>> list(flatten(a))
[1, 2, 2, 2, 4]

与其他解决方案不同,这个也适用于字符串:

>>> lis = [1,[2,2,2],"456"]
>>> list(flatten(lis))
[1, 2, 2, 2, '456']

7
如果使用Python 3,请将basestring替换为str - yemi.JUMP

22

如果您使用的是 python < 3,那么可以执行以下操作:

from compiler.ast import flatten
list = [1,[2,2,2],4]
print flatten(list)

Python 3.0 中的手动等效方法如下(摘自这个答案):

def flatten(x):
    result = []
    for el in x:
        if hasattr(el, "__iter__") and not isinstance(el, str):
            result.extend(flatten(el))
        else:
            result.append(el)
    return result

 print(flatten(["junk",["nested stuff"],[],[[]]]))  
你甚至可以在列表推导式中做同样的事情:
list = [1,[2,2,2],4]
l = [item for sublist in list for item in sublist]

这与以下内容相当:

l = [[1], [2], [3], [4], [5]]
result = []
for sublist in l:
    for item in sublist:
        result.append(item)

print(result)

1
那个导入"compiler.ast"的语句真是让我大吃一惊!...它甚至比所有包括yield的答案都要简单。但有一件事,我尝试了列表推导式的答案(因为我之前学过Haskell),但它却报错:"TypeError: 'int' object is not iterable" =( - compski

10

在 Python 中,我们可以通过以下简单的方法将嵌套列表转换为单个列表:

from functools import reduce

some_list = [[14], [215, 383, 87], [298], [374], [2,3,4,5,6,7]]
single_list = reduce(lambda x,y: x+y, some_list)
print(single_list)

输出:[14, 215, 383, 87, 298, 374, 2, 3, 4, 5, 6, 7]


6
from nltk import flatten

example_list = [1, [2, 3], 3]
flattened_list = flatten(example_list)
print(flattened_list)

输出:[1, 2, 3, 3]


2
itertools.chain()函数会迭代输入列表中的每个项目(请参阅我提供的文档)。由于无法遍历整数,因此会引发错误。这就是为什么在第二个示例中,您只有列表中的列表,没有单独的整数,因此实际上没有遍历整数。
要使其正常工作,您可以使用递归:
>>> from collections import Iterable
>>> def flat(lst):
...     for parent in lst:
...         if not isinstance(i, Iterable):
...             yield parent
...         else:
...             for child in flat(parent):
...                 yield child
...
>>> list(flat(([1,[2,2,2],4]))
[1, 2, 2, 2, 4]

2
您不必使用append,只需要使用extend即可。
def flatten(nasted_list):
    """
    input: nasted_list - this contain any number of nested lists.
    ------------------------
    output: list_of_lists - one list contain all the items.
    """

    list_of_lists = []
    for item in nasted_list:
        list_of_lists.extend(item)
    return list_of_lists

test1 = flatten([[1,2,3],[4,5,6]])
print(test1)

输出结果:[1, 2, 3, 4, 5, 6]


2

使用 more_itertools 库

import more_itertools

nested_test1 = [[-1, -2], [1, 2, 3, [4, (5, [6, 7])]], (30, 40), [25, 35]]
nested_test2 = [1,[2,2,2],4]
lis = [1,[2,2,2],"456"]

print(list(more_itertools.collapse(nested_test1)))
print(list(more_itertools.collapse(nested_test2)))
print(list(more_itertools.collapse(lis)))

输出

[-1, -2, 1, 2, 3, 4, 5, 6, 7, 30, 40, 25, 35]
[1, 2, 2, 2, 4]
[1, 2, 2, 2, '456']

0
old_list = [1,2,3,['a','b'],4,5,6,['c','d',[11,22,33,'aa','bb','cc',[111,222,333,['aaa','bbb','ccc',[1111,2222,['aaaa','bbbb',[11111,22222]]]]]],'e']]

new_list = []

def my_fun(temp_list):
    for ele in temp_list:
        if type(ele) == list:
            my_fun(ele)
        else:
            new_list.append(ele)


my_fun(old_list)
print old_list
print new_list

output:
old_list = [1, 2, 3, ['a', 'b'], 4, 5, 6, ['c', 'd', [11, 22, 33, 'aa', 'bb', 'cc', [111, 222, 333, ['aaa', 'bbb', 'ccc', [1111, 2222, ['aaaa', 'bbbb', [11111, 22222]]]]]], 'e']]
new_list = [1, 2, 3, 'a', 'b', 4, 5, 6, 'c', 'd', 11, 22, 33, 'aa', 'bb', 'cc', 111, 222, 333, 'aaa', 'bbb', 'ccc', 1111, 2222, 'aaaa', 'bbbb', 11111, 22222, 'e']

使用递归将多层嵌套列表转换为单层切片列表。

0
请使用pipe包。
from pipe import chain


lst=[[1,2], [3,4], [5,6]]

list(lst|chain)

[1, 2, 3, 4, 5, 6]


0
list1 = [[1,2,3], 2, 4,[4,5,6],[7,8,9]] 
flat_list = []
for item in list1:
    if type(item) == list:
        flat_list = flat_list+item
    else:
        flat_list.append(item)

输出:[1, 2, 3, 2, 4, 4, 5, 6, 7, 8, 9]


1
你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接