• day14 列表/集合/字典推导式&生成器表达式&生成器函数


    推导式

    推导式的定义: 通过一行循环判断,遍历一系列数据的方式

    推导式的语法:

    val for val in Iterable

    三种方式:

      [val for val in Iterable]

      {val for val in Iterable}

      {k:v for k,v in Iterable}

    列表推导式

    1.单循环推导式

    将[1,2,3,4,5] -> [3,6,9,12,15]

    复制代码
    # 1.单循环推导式 [1,2,3,4,5] -> [3,6,9,12,15]
    lst = [1,2,3,4,5]
    lst_new = []
    for i in lst:
        res = i * 3
        lst_new.append(res)
    print(lst_new)
    
    # 改写成推导式
    lst = [i*3 for i in lst]
    print(lst)
    复制代码

    2.带有判断条件的单循环推导式

    复制代码
    # 2.带有判断条件的单循环推导式 (只能是单项分支,接在for后面)
    lst = [1,2,3,4,5,6,7,8]
    lst_new = []
    for i in lst:
        if i % 2 == 1:
            lst_new.append(i)
    print(lst_new)
    
    # 改写成推导式
    lst = [i for i in lst if i % 2 == 1]
    print(lst)
    复制代码

    3.双循环推导式

    复制代码
    # 3. 双循环推导式
    lst1 = ["A","B","C","D"]
    lst2 = ["X","Y","Z","Q"]
    # "谁"❤"谁"
    lst_new = []
    for i in lst1:
        for j in lst2:
            strvar = i + "❤" + j
            lst_new.append(strvar)
    print(lst_new)
    
    # 改写成推导式
    lst = [i + "❤" + j for i in lst1 for j in lst2]
    print(lst)
    复制代码

    4.带有判断条件的多循环推导式

    复制代码
    # 4.带有判断条件的多循环推导式
    lst_new = []
    for i in lst1:
        for j in lst2:
            if lst1.index(i) == lst2.index(j):
                strvar = i + "❤" + j
                lst_new.append(strvar)        
    print(lst_new)
    
    # 改写成推导式
    lst = [ i + "❤" + j for i in lst1 for j in lst2 if lst1.index(i) == lst2.index(j) ]
    print(lst)
    复制代码

    推导式练习题

    1.{'x': 'A', 'y': 'B', 'z': 'C' } 把字典写成x=A,y=B,z=C的列表推导式

    # 使用等号"="进行拼接
    lst = [k + "=" + v for k,v in dic.items()]
    print(lst)

    2.x是0-5之间的偶数,y是0-5之间的奇数 把x,y组成一起变成元组,放到列表当中

    复制代码
    # 方法一
    lst = [(x,y) for x in range(6) for y in range(6) if x % 2 == 0 and y % 2 == 1]
    print(lst)
    
    # 方法二
    lst = [(x,y) for x in range(6) if x % 2 == 0 for y in range(6) if y % 2 == 1]
    print(lst)
    复制代码

    3.使用列表推导式 制作所有99乘法表中的运算

    # for前面是一个format字符串的格式化
    lst = ["{}*{}={:2d} ".format(i,j,i*j) for i in range(9,0,-1) for j in range(1,i+1) ]
    print(lst)

    4.求M,N中矩阵和元素的乘积

    M = [  [1,2,3], 
         [4,5,6], 
         [7,8,9] ] 

    N = [  [2,2,2], 
         [3,3,3], 
         [4,4,4] ] 
    =>实现效果1 [2, 4, 6, 12, 15, 18, 28, 32, 36]
    =>实现效果2 [[2, 4, 6], [12, 15, 18], [28, 32, 36]]

    复制代码
    # 实现思路
    M = [[1,2,3],[4,5,6],[7,8,9]]
    N = [[2,2,2],[3,3,3],[4,4,4]]
    
    """
    M[0][0] * N[0][0] => 2
    M[0][1] * N[0][1] => 4
    M[0][2] * N[0][2] => 6
    
    M[1][0] * N[1][0] => 12
    M[1][1] * N[1][1] => 15
    M[1][2] * N[1][2] => 18
    
    M[2][0] * N[2][0] => 28
    M[2][1] * N[2][1] => 32
    M[2][2] * N[2][2] => 36
    
    外层的循环动的慢,内层的循环动的快,
    外层的循环动一次,内层的循环动3次,
    利用这个规律取出对应下标,乘积即可.
    """
    
    # 效果一  [2, 4, 6, 12, 15, 18, 28, 32, 36]
    lst = [M[i][j] * N[i][j] for i in range(3) for j in range(3)]
    print(lst)
    
    # 效果二 [[2, 4, 6], [12, 15, 18], [28, 32, 36]]
    # 1 . 先遍历出三个空列表
    lst = [  [] for i in range(3)  ]   =>  [ [],[],[] ]
    # 2 . 把空列表中的数据在通过推导式算出所有内容
    lst = [ [M[i][j] * N[i][j] for j in range(3)]  for i in range(3) ]
    print(lst)
    复制代码

    集合推导式

    关于集合推导式的一个示例:

    1.集合有自动去重的效果

    2.用三元表达式+推导式即可实现

    复制代码
    """
    案例:
        满足年龄在18到21,存款大于等于5000 小于等于5500的人,
        开卡格式为:尊贵VIP卡老x(姓氏),否则开卡格式为:普通用户卡老x(姓氏)
        把开卡的种类统计出来
    """
    listvar = [
        {"name":"彭云飞","age":18,"money":10000},
        {"name":"夏圣钦","age":19,"money":5100},
        {"name":"陈正正","age":20,"money":4800},
        {"name":"王添龙","age":21,"money":2000},
        {"name":"万潇阳","age":18,"money":20}
    ]
    
    # 常规写法
    setvar = set()
    for i in listvar:
        if 18 <= i["age"] <= 21 and  5000 <= i["money"] <= 5500:
            res = "尊贵VIP卡老" + i["name"][0]
        else:
            res = "普通用户卡老" + i["name"][0]
        setvar.add(res)
    print(setvar)
    
    # 改写成集合推导式
    # {三元运算符 + 推导式}
    setvar = { "尊贵VIP卡老" + i["name"][0] if 18 <= i["age"] <= 21 and  5000 <= i["money"] <= 5500 else "普通用户卡老" + i["name"][0] for i in listvar }
    print(setvar)
    复制代码

    字典推导式

    1.enumerate

    功能:

      枚举 ; 将索引号和iterable中的值,一个一个拿出来配对组成元组放入迭代器中
    参数:

      iterable: 可迭代性数据 (常用:迭代器,容器类型数据,可迭代对象range) 
      start: 可以选择开始的索引号(默认从0开始索引)
    返回值:迭代器

    enumerate形成字典推导式示例:

    复制代码
    from collections import Iterator
    lst = ["东邪","西毒","南帝","北丐"]
    
    # 基本使用
    it = enumerate(lst) # [(0, '东邪'), (1, '西毒'), (2, '南帝'), (3, '北丐')]
    print(isinstance(it,Iterator))
    
    # for + next
    for i in range(4):
        print(next(it))
    # list
    """start可以指定开始值,默认是0"""
    it = enumerate(lst,start=1)
    print(list(it)) # [(1, '东邪'), (2, '西毒'), (3, '南帝'), (4, '北丐')]
    
    # enumerate 形成字典推导式 变成字典
    dic = { k:v for k,v in enumerate(lst,start=1) }
    print(dic) # {1: '东邪', 2: '西毒', 3: '南帝', 4: '北丐'}
    
    # dict 强制变成字典
    dic = dict(enumerate(lst,start=1))
    print(dic) # {1: '东邪', 2: '西毒', 3: '南帝', 4: '北丐'}
    复制代码

    2.zip

    zip(iterable, ... ...)
      功能:将多个iterable中的值,一个一个拿出来配对组成元组放入迭代器中

      参数:iterable: 可迭代性数据 (常用:迭代器,容器类型数据,可迭代对象range) 

      返回值: 迭代器

      特征:如果找不到对应配对的元素,当前元素会被舍弃

    复制代码
    lst1=["Fly","1dao","Hurt","Mojo"]
    lst2=["Snow","Song","Giao"]
    lst3=["770","JieJ"]
    
    it = zip(lst1,lst2,lst3)
    print(list(it)) # [('Fly', 'Snow', '770'), ('1dao', 'Song', 'JieJ')]
    # zip形成字典推导式 变成字典
    lst1=["Fly","1dao","Hurt","Mojo"]
    lst2=["Snow","Song","Giao"]
    dic={k:v for k,v in zip(lst1,lst2)}
    print(dic) # {'Fly': 'Snow', '1dao': 'Song', 'Hurt': 'Giao'}
    # dict强制变为字典
    dic = dict(zip(lst1,lst2))
    print(dic) # {'Fly': 'Snow', '1dao': 'Song', 'Hurt': 'Giao'}
    复制代码

    生成器表达式 

    1.生成器本质是迭代器,允许自定义逻辑的迭代器
    2.迭代器和生成器区别:
      迭代器本身是系统内置的.重写不了.而生成器是用户自定义的,可以重写迭代逻辑
    3.生成器可以用两种方式创建:
      (1)生成器表达式 (里面是推导式,外面用圆括号)
      (2)生成器函数 (用def定义,里面含有yield)

    4.生成器表达式<=>元组推导式

    gen = (i*2 for i in range(1,11))

    生成器函数

    yield 类似于 return
    共同点在于:执行到这句话都会把值返回出去
    不同点在于:yield每次返回时,会记住上次离开时执行的位置 , 下次在调用生成器 , 会从上次执行的位置往下走
    而return直接终止函数,每次重头调用.
    yield 6 和 yield(6) 2种写法都可以 yield 6 更像 return 6 的写法 推荐使用

    1.生成器函数的基本语法:

    复制代码
    # 定义一个生成器函数
    def mygen():
        print(111)
        yield 1
    
        print(222)
        yield 2
        
        print(333)
        yield 3
    
    # 初始化生成器函数,返回生成器对象,简称生成器
    gen = mygen() # gen是生成器对象(生成器)
    print(isinstance(gen,Iterator)) # gen是一个迭代器
    
    # 使用next调用
    res = next(gen)
    print(res)
    res = next(gen)
    print(res)
    res = next(gen)
    print(res)
    复制代码

    关于生成器函数的执行流程:

    代码解析:
    初始化生成器函数 -> 生成器(通过next调用)
    第一次调用生成器
    res = next(gen) => print(111) yield 1 保存当前代码状态14行,并将1这个值返回 print(1) ,等待下一次调用
    第二次调用生成器
    res = next(gen) => 从上一次保存的状态14行继续向下执行
    print(222) yield 2 保存当前代码状态17行,并将2这个值返回 print(2) ,等待下一次调用
    第三次调用生成器
    res = next(gen) => 从上一次保存的状态17行继续向下执行
    print(333) yield 3 保存当前代码状态20行,并将3这个值返回 print(3) ,等待下一次调用
    第四次调用生成器
    因为没有更多yield返回数据了,所以直接报错.

    2.send()的用法

    next和send区别:
    next 只能取值
    send 不但能取值,还能发送值
    send注意点:
    第一个 send 不能给 yield 传值 默认只能写None
    最后一个yield 接受不到send的发送值
    send 是给上一个yield发送值

    复制代码
    def mygen():
        print("process start")
        res = yield 100
        print(res,"内部打印1")
        
        res = yield 200
        print(res,"内部打印2")
        
        res = yield 300
        print(res,"内部打印3")
        print("process end")
    
    # 初始化生成器函数 -> 生成器
    gen = mygen()
    # 在使用send时,第一次调用必须传递的参数是None(硬性语法),因为第一次还没有遇到上一个yield
    '''第一次调用'''
    res = gen.send(None) #<=> next(gen)
    print(res)
    '''第二次调用'''
    res = gen.send(101) #<=> next(gen)
    print(res)
    '''第三次调用'''
    res = gen.send(201) #<=> next(gen)
    print(res)
    '''第四次调用, 因为没有更多的yield返回数据了,所以StopIteration'''
    res = gen.send(301) #<=> next(gen)
    print(res)
    复制代码

    初始化生成器函数,返回生成器对象
    第一次调用时,
    print("process start")
    res = yield 100 记录当前代码状态81行,返回100,等待下一次调用
    res = 100 print(100)

    第二次调用时,
    把101 发送给上一个yield保存的状态81行 res = 101 从81行继续往下走
    print(101,"内部打印1")
    res = yield 200 记录当前代码状态84行,返回200,等待下一次调用
    res = 200 print(200)

    第三次调用时,
    把201 发送给上一个yield保存的状态84行 res = 201 从84行继续往下走
    print(201,"内部打印2")
    res = yield 300 记录当前代码状态87行,返回300,等待下一次调用
    res = 300 print(300)

    3.yield from  将一个可迭代对象变成一个迭代器返回

    复制代码
    def mygen():
        yield from ["Alan","Fly","Hurt","1dao"]
        
    gen = mygen()
    print(next(gen))
    print(next(gen))
    print(next(gen))
    print(next(gen))
    复制代码

    4.示例:用生成器描述斐波那契数列

    复制代码
    """1 1 2 3 5 8 13 21 34 ... """
    """
    yield 1
    a,b = b,a+b = 1,1
    
    yield 1
    a,b = b,a+b = 1,2
    
    yield 2
    a,b = b,a+b = 2,3
    
    yield 3
    a,b = b,a+b = 3,5
    
    yield 5
    ....
    
    """
    
    def mygen(maxlen):
        a,b = 0,1
        i = 0
        while i < maxlen:
            yield b
            a,b = b,a+b
            i+=1
        
    # 初始化生成器函数 -> 生成器
    gen = mygen(10)
    
    for i in range(3):
        print(next(gen))
  • 相关阅读:
    bzoj4849: [Neerc2016]Mole Tunnels
    bzoj 4069~4071 APIO2015
    bzoj 4885: [Lydsy2017年5月月赛]长方体
    bzoj4891: [Tjoi2017]龙舟
    bzoj4892: [Tjoi2017]dna
    bzoj 3159: 决战
    bzoj3672: [Noi2014]购票
    bzoj4738: 汽水
    bzoj 4737: 组合数问题
    bzoj 4872: [Shoi2017]分手是祝愿
  • 原文地址:https://www.cnblogs.com/liya1014/p/13367664.html
Copyright © 2020-2023  润新知