18

以前也有人问过类似的问题,但这些问题的解决方案不适用于我的用例(例如,从 Python 中的列表列表中制作一个扁平列表和在 Python 中扁平化一个浅列表。我有一个字符串列表和列表,其中嵌入列表也可以包含字符串和列表。我想把它变成一个简单的字符串列表,而不是将字符串拆分成字符列表。

import itertools

list_of_menuitems = ['image10', ['image00', 'image01'], ['image02', ['image03', 'image04']]]
chain = itertools.chain(*list_of_menuitems)

结果列表:

['i', 'm', 'a', 'g', 'e', '1', '0', 'image00', 'image01', 'image02', ['image03', 'image04']]

预期结果:

['image10', 'image00', 'image01', 'image02', 'image03', 'image04']

最好的(Pythonic)方法是什么?

4

5 回答 5

14

经常重复的flatten功能可以通过简单的修改应用于这种情况。

from collections import Iterable
def flatten(coll):
    for i in coll:
            if isinstance(i, Iterable) and not isinstance(i, basestring):
                for subc in flatten(i):
                    yield subc
            else:
                yield i

basestring将确保strunicode对象都不会被拆分。

还有一些版本依赖于i没有该__iter__属性。我不知道这一切,因为我认为str现在有那个属性。但是,值得一提。

(请支持链接的答案。)

于 2013-07-25T17:39:09.367 回答
11

使用递归。

def flatten(A):
    rt = []
    for i in A:
        if isinstance(i,list): rt.extend(flatten(i))
        else: rt.append(i)
    return rt

测试:

>>> list_of_menuitems = ['image10', ['image00', 'image01'], ['image02', ['image0
3', 'image04']]]
>>> flattern(list_of_menuitems)
['image10', 'image00', 'image01', 'image02', 'image03', 'image04']
于 2013-07-25T20:09:32.590 回答
8

以下适用于字符串(并且很容易适应其他类型):

def flatten_to_strings(listOfLists):
    """Flatten a list of (lists of (lists of strings)) for any level 
    of nesting"""
    result = []

    for i in listOfLists:
        # Only append if i is a basestring (superclass of string)
        if isinstance(i, basestring):
            result.append(i)
        # Otherwise call this function recursively
        else:
            result.extend(flatten_to_strings(i))
    return result

flatten_to_strings(list_of_menuitems)
Out[2]: ['image10', 'image00', 'image01', 'image02', 'image03', 'image04']
于 2013-07-25T17:11:08.737 回答
5

在一种特殊情况下,当列表项都不包含以下分隔符之一时[]',您可以使用以下技巧。我没有对其进行分析,但很明显,这将比明显且更清晰的递归解决方案具有更好的性能。

>>> str(list_of_menuitems).translate(None,"[]'").split(',')
['image10', ' image00', ' image01', ' image02', ' image03', ' image04']

我同意,这是一个肮脏的 hack,但不费吹灰之力就可以完成这项工作。

于 2013-07-25T17:23:20.337 回答
1

这是一个通用的递归展平,可用于处理应该或不应该展平的任何类型组合:

import collections
def generic_flatten(seq, flatten_types=(tuple,list,set),atom_types=(basestring,dict),fixtype=True):
    newseq = []
    for item in seq:
        if (not isinstance(collections.Iterable)) or any(isinstance(i,t) for t in atom_types):
           newseq.append(item)
        elif any(isinstance(i,t) for t in flatten_types): # set flatten_types to (object,) or (collections.Iterable,) to disable check
           newseq.extend(generic_flatten(item, flatten_types, atom_types,fixtype)
    if fixtype and type(newseq) is not type(seq):
       newseq = type(seq)(newseq)
    return newseq

yield并且chain可以用来创建一个通用的基于迭代器的版本。

于 2013-07-25T17:26:36.153 回答