使用生成器展开嵌套序列

问题:展开如下列表

ls1 = [1, 2, 3]
ls2 = [1, [2, 3], 4, [5, 6]]
ls3 = [1, [2, [3, 4]], 5, [6, 7, 8]]

if… else 版本:

def expandlist(nested):
    for sublist in nested:
        if isinstance(sublist, list): 
        # 可以使用 collections.abc 基类的 Iterable 来判断
            for item in expandlist(sublist):
                yield item
        else:
            yield sublist

try … except 版本

def nest_list(nested):
    try:
        for sublist in nested:
            for item in nest_list(sublist):
                yield item
    except TypeError:
        yield nested

代码分析

  1. 使用try…except… 展开嵌套列表,无需判断sublist是否为list,利用sublist 为非迭代类型触发异常yield 数据,这里是int 类型。
  2. if…else 版本判断sublist 是否是列表,决定是否调用递归。
  3. 结束递归条件都是数据无法再拆解则利用异常或条件判断yield 数据。
  4. 主程序中调用该生成器函数得到的数据是生成器里的第1层循环(非递归)传回的数据,递归嵌套中yield 返回的数据插入到上层递归的生成器中。所以代码可以看做是利用生成器的递归使用解包嵌套列表。
for item in nest_list(sublist):
     yield item
  1. 递归结束条件:
try… except
except TypeError:
    yield nested
if … else
 if isinstance(sublist, list):
            for item in expandlist(sublist):
                yield item
        else:
            yield sublist

调试过程:

第1层递归

在这里插入图片描述

第2层递归

在这里插入图片描述

第3层递归

在这里插入图片

完整代码:

# coding:utf-8

from collections.abc import Iterable


def nest_list(nested):
    try:
        for sublist in nested:
            for item in nest_list(sublist):
                yield item
    except TypeError:
        yield nested


def expandlist(nested):
    for sublist in nested:
        if isinstance(sublist, list):
            for item in expandlist(sublist):
                yield item
        else:
            yield sublist


if __name__ == '__main__':
    ls1 = [1, 2, 3]
    ls2 = [1, [2, 3], 4, [5, 6]]
    ls3 = [1, [2, [3, 4]], 5, [6, 7, 8]]

    for n in expandlist(ls3):
        print(n, end='\t')

总结:

使用递归展开嵌套列表,实际上是使用了生成器的嵌套。每一层递归都返回了一个生成器。yield 语句更像是一个带断点的return语句,当迭代器中还有数据时,会从上次的断点处执行。否则使用return语句会从头开始执行,造成数据重复。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值