2017-01-23 60 views
0

我需要遞歸壓扁名單列表:壓扁包含的元組,信件列表和整數

列表看起來像之前:

L=[1,[2,[‘a’,(3,’b’)]],(5,6),([11,22])] 

後:

Lflat=[1,2,’a’,(3,’b’),(5,6),([11,22])] 

我我的代碼遇到問題(lst1是空的lst1)

def list_flatten(lst,lst1): 
    for item in lst: 
     if type(item) == tuple: 
      print(item) 
      lst1.append(item) 
     elif type(item) == list: 
      list_flatten(item,lst1) 
     else: 
      lst1.append(item) 
    return lst1 

這將返回以下:

OUTPUT:[1, 2, 'a', (3, 'b'), (5, 6), 11, 22]

導致我找出([])被認爲是一個列表,而不是一個元組。

現在我的問題如下:

  1. 說我定義LST1 = []主程序裏面。我如何使它 它,所以遞歸不會每次迭代清空列表?
  2. 爲什麼([])被視爲一個列表?
+1

'([])'是一個列表,因爲[元組由數值的由逗號分隔的](https://docs.python.org/2/tutorial /datastructures.html#tuples-and-sequences),並且這裏沒有逗號。在這種情況下,括號只是強制評估*裏面的*括號,它是一個列表。 –

+1

'([],)'是一個元組。別擔心,這讓每個人都感到困惑。 –

+1

@DavidZemens確實如此,但函數會改變'lst1',所以它確實不需要返回任何東西。 –

回答

2

您的list_flatten函數改變了lst1的參數,所以您並不需要返回任何東西。你可以這樣調用:

L = [1,[2,['a',(3,'b')]],(5,6),([11,22])] 

def list_flatten(lst, lst1): 
    for item in lst: 
     if isinstance(item, list): 
      list_flatten(item, lst1) 
     else: 
      lst1.append(item) 

Lflat = [] 
list_flatten(L, Lflat) 
print(Lflat) 

輸出

[1, 2, 'a', (3, 'b'), (5, 6), 11, 22] 

我們推薦使用isinstance,而不是type,因爲這使代碼更靈活:它也將與list派生對象。

我們可以重新寫的功能,使您不必在lst1經過:

def list_flatten(lst, lst1=None): 
    if lst1 is None: 
     lst1 = [] 
    for item in lst: 
     if isinstance(item, list): 
      list_flatten(item, lst1) 
     else: 
      lst1.append(item) 
    return lst1 

Lflat = list_flatten(L) 
print(Lflat) 

我們給lst1None和我們遞歸的最高級別重新綁定默認值名稱lst1到一個空的列表來收集結果。

我們不能給lst1默認值[]。這是因爲默認參數是在編譯函數時創建的,而不是在函數被調用時創建的,並且如果我們給lst1默認值[],那麼在每次調用時將使用相同的列表。它看起來像我們第一次使用list_flatten時所做的那樣,但在隨後的調用中它不會像預期的那樣運行。這是一個簡短的演示。

L = [1,[2,['a',(3,'b')]],(5,6),([11,22])] 

def list_flatten(lst, lst1=[]): 
    for item in lst: 
     if isinstance(item, list): 
      list_flatten(item, lst1) 
     else: 
      lst1.append(item) 
    return lst1 

Lflat = list_flatten(L) 
print(Lflat) 
Lflat = list_flatten(L) 
print(Lflat) 

輸出

[1, 2, 'a', (3, 'b'), (5, 6), 11, 22] 
[1, 2, 'a', (3, 'b'), (5, 6), 11, 22, 1, 2, 'a', (3, 'b'), (5, 6), 11, 22] 

正如你所看到的,lst1已經從第一個呼叫保留其內容。有關此重要主題的更多信息,請參閱「Least Astonishment」 and the Mutable Default Argument。有些時候這種行爲是可取的,但在這種情況下,向代碼添加註釋是明智的,即您有意使用可變默認參數。


還有一種方法是使list_flatten成發電機,並收集其輸出到一個列表:

def list_flatten(lst): 
    for item in lst: 
     if isinstance(item, list): 
      yield from list_flatten(item) 
     else: 
      yield item 

Lflat = list(list_flatten(L)) 
print(Lflat) 

在最新版本的Python可以用[*list_flatten(L)]取代list(list_flatten(L))

Python 2裏沒有yield from,但你可以替換該行:

for u in list_flatten(item): 
    yield u 

如果你實際上並不需要的列表,你可以調用發電機是這樣的:

for u in list_flatten(L): 
    print(u) 

輸出

1 
2 
a 
(3, 'b') 
(5, 6) 
11 
22 
1

你可以注意到,你需要的是:

  • 如果列表爲空,原樣返回
  • 如果它有一個單一的元素,該元素是不是列表,返回列表不變
  • 其他壓平第一元件,壓平的列表的末尾和將兩者連接起來的子列表

在Python代碼,它導致:

def flatten(L): 
    if len(L) == 0: return L 
    elif len(L) == 1 and not isinstance(L[0], list): return L 
    else: 
     return (flatten(L[0] if isinstance(L[0], list) 
       else [L[0]]) + flatten(L[1:])) 

它給預期:

>>> L = [1, 2, 'a', (3, 'b'), (5, 6), ([11, 22],)] 
>>> flatten(L) 
[1, 2, 'a', (3, 'b'), (5, 6), ([11, 22],)]