简体   繁体   English

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

[英]Flattening a list that contains lists of tuples, letters and integers

I need to flatten a list recursively: 我需要递归整理列表:

Before the list looks like: 在列表看起来像之前:

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

After: 后:

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

I've come across an issue with my code (lst1 is an empty lst1) 我的代码遇到问题(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

This returns the following: 这将返回以下内容:

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

Which lead me to find out that ([]) is considered a list, not a tuple. 这使我发现([])被认为是列表,而不是元组。

Now my questions are as following: 现在我的问题如下:

  1. Say I were to define lst1=[] inside the main program. 假设我要在主程序中定义lst1 = []。 How do I make it so the recursion doesn't empty the list out every iteration? 我如何做到这一点,以便递归不会在每次迭代中清空列表?
  2. Why is ([]) considered a list? 为什么([])被视为列表?

Your list_flatten function mutates the lst1 argument, so you don't really need to return anything. 您的list_flatten函数会lst1参数,因此您实际上不需要返回任何内容。 You can call it like this: 您可以这样称呼它:

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)

output 产量

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

It's recommended to use isinstance rather than type because that makes the code more versatile: it will also work with objects derived from list . 建议使用isinstance而不是type因为这会使代码更具通用性:它也可用于源自list对象。

We can re-write the function so that you don't need to pass in lst1 : 我们可以重新编写该函数,以便您无需传递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)

We give lst1 a default value of None and on the top level of the recursion we re-bind the name lst1 to an empty list to collect the results. 我们给lst1一个默认值None ,在递归的顶层,我们将名字lst1重新绑定到一个空列表中以收集结果。

We can't give lst1 a default value of [] . 我们不能将lst1的默认值lst1 [] That's because default args are created when the function is compiled, not when the function is called, and if we gave lst1 a default value of [] that same list would get used on every call. 这是因为默认args是在编译函数时创建的,而不是在调用函数时创建的,并且如果我们为lst1默认值[] ,则每次调用都会使用相同的列表。 It would look like it does what we want the first time we used list_flatten , but it would not behave as desired on subsequent calls. 看起来像第一次使用list_flatten ,我们可以list_flatten它,但是在随后的调用中却无法达到预期的效果。 Here's a short demo. 这是一个简短的演示。

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)

output 产量

[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]

As you can see, lst1 has retained its contents from the first call. 如您所见, lst1保留了第一个调用的内容。 For more info on this important topic, please see “Least Astonishment” and the Mutable Default Argument . 有关此重要主题的更多信息,请参见“最小惊讶”和可变默认参数 There are times when this behviour is desirable, but in such cases it's wise to add a comment to your code that you're intentionally using a mutable default argument. 有时候,这种行为是可取的,但是在这种情况下,明智的做法是在代码中添加注释,而您有意使用可变的默认参数。


Yet another way is to make list_flatten into a generator, and collect its output into a list: 另一种方法是使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)

In recent versions of Python you can replace list(list_flatten(L)) with [*list_flatten(L)] . 在最新版本的Python中,您可以使用[*list_flatten(L)]替换list(list_flatten(L))

Python 2 doesn't have yield from , but you can replace that line with: Python 2没有yield from产生yield from ,但是您可以将该行替换为:

for u in list_flatten(item):
    yield u

If you don't actually need the list you can call the generator like this: 如果您实际上不需要此列表,则可以这样调用生成器:

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

output 产量

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

You can note that what you need is: 您可以注意到,您需要的是:

  • if the list is empty, return it unchanged 如果列表为空,则保持不变
  • if it has one single element and that element is not a list, return the list unchanged 如果它只有一个元素并且该元素不是列表,则返回列表不变
  • else flatten first element, flatten the end of the list and concatenate the two sublists 否则将第一个元素展平,将列表末尾展平并连接两个子列表

In Python code, it leads to: 在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:]))

it gives as expected: 它给出了预期的结果:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM