2013-07-25 152 views
7

以前也有类似的问题,但这些解决方案对我的用例不起作用(例如,Making a flat list out of list of lists in PythonFlattening a shallow list in 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)的方式来做到这一点?

+0

参见:http://stackoverflow.com/questions/16176742/python-3-replacement-for-deprecated-compiler-ast-flatten-function –

+0

我同意它几乎是http://stackoverflow.com/questions/5286541/how-can-i-flatten-lists-without-splitting-strings的重复。这个问题中缺少的一个方面(在提问之前我没有找到)是任意级别的嵌套问题。然而,解决方案张贴在那里(和在http:// stackoverflow。com/questions/16176742/python-3-replacement-for-deprecated-compiler-ast-flatten-function)至少在我提供的情况下可以很好地处理这个问题。 –

+0

OP:使用'basestring'而不是'str',这样你就不会分裂'unicode'。 – 2rs2ts

回答

4

以下作品串(并会很容易地适应其他类型):

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'] 
+2

这有一些冗余 - isinstance考虑到继承,你可以将无测试切换到递归分支 – Marcin

+0

@marcin感谢您的评论。我调整了我的代码来解决这些问题。 –

1

在一个专业的情况下,当没有列表项包含以下分隔符[]'之一,你可以使用下面的黑客攻击。我没有分析它,但它看起来很明显,这将比明显和更清晰的递归解决方案有更好的性能。

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

我同意,这是一个肮脏的黑客攻击,但没有多少努力。

+0

我会低估这一点,除非你明确解释了它的缺点。所以这是一个很好的参考我想。 – 2rs2ts

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 

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

9

经常重复的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现在具有该属性。但是,值得一提的是。

(请注意链接的答案。)

+1

我的确怀疑,只是链接到答案本身会更好,这样它就可以作为方向,而不会引入重复。 –

2

使用递归。

def flattern(A): 
    rt = [] 
    for i in A: 
     if isinstance(i,list): rt.extend(flattern(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']