把包含列表、元组、字母和整数的列表转成平整的列表

2024-04-18 16:14:33 发布

您现在位置:Python中文网/ 问答频道 /正文

我需要递归地展平列表:

在列表如下所示之前:

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. 为什么([])被认为是一个列表?你知道吗

Tags: 代码in列表forifdeftypeitem
2条回答

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

  • 如果列表为空,则原封不动地返回
  • 如果它只有一个元素,而该元素不是列表,则返回列表
  • 否则,展平第一个元素,展平列表的结尾并连接两个子列表

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

你的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一个默认值[]。这是因为默认参数是在编译函数时创建的,而不是在调用函数时创建的,如果我们给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。有时,这种behviour是可取的,但在这种情况下,明智的做法是在代码中添加注释,说明您有意使用可变的默认参数。你知道吗


另一种方法是将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

相关问题 更多 >