2017-01-23 62 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],)]