展平包含元组,字母和整数列表的列表

时间:2017-01-23 14:26:22

标签: python list recursion tuples

我需要递归地压缩列表:

在列表显示之前:

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

返回以下内容:

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

这让我发现([])被认为是一个列表,而不是一个元组。

现在我的问题如下:

  1. 说我要在主程序中定义lst1 = []。我该怎么做 那么递归不会在每次迭代时清空列表吗?
  2. 为什么([])被认为是一个列表?

2 个答案:

答案 0 :(得分: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)

我们给lst1一个默认值None,在递归的顶层我们将名称lst1重新绑定到一个空列表以收集结果。

我们无法为lst1提供默认值[]。这是因为默认args是在编译函数时创建的,而不是在函数被调用时创建的,如果我们给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(list_flatten(L))替换为[*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 :(得分:1)

您可以注意到您需要的是:

  • 如果列表为空,则将其保持不变
  • 如果它有一个单独的元素且该元素不是列表,则返回列表不变
  • else展平第一个元素,展平列表的末尾并连接两个子列表

在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],)]