2013-07-25 151 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']