在Python中展平字符串列表和字符串列表

Flatten a list of strings and lists of strings and lists in Python

本问题已经有最佳答案,请猛点这里访问。

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

1
2
3
4
import itertools

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

结果列表:

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

预期结果:

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

做这个最好的方法是什么?


经常重复的flatten函数只需简单的修改就可以应用于这种情况。

1
2
3
4
5
6
7
8
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现在有了这个属性。但值得一提。

(请向上投票链接的答案。)


使用递归。

1
2
3
4
5
6
def flattern(A):
    rt = []
    for i in A:
        if isinstance(i,list): rt.extend(flattern(i))
        else: rt.append(i)
    return rt

试验:

1
2
3
4
>>> list_of_menuitems = ['image10', ['image00', 'image01'], ['image02', ['image0
3'
, 'image04']]]
>>> flattern(list_of_menuitems)
['image10', 'image00', 'image01', 'image02', 'image03', 'image04']


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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']


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

1
2
3
4
5
6
7
8
9
10
11
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

yieldchain可用于创建基于迭代器的通用版本。


在一个特殊的情况下,当列表项中没有包含下列定界符之一[]'时,可以使用下面的hack。我还没有对它进行分析,但很明显,这比明显的、更清晰的递归解决方案具有更好的性能。

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

我同意,这是一个肮脏的黑客,但做这项工作,没有太多的努力。