zoukankan      html  css  js  c++  java
  • 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))
  • 相关阅读:
    专职DBA-MySQL体系结构与基本管理
    JSON
    MIME类型
    文件上传下载
    response常用的方法
    2020.11.27小记
    HTTP请求状态码
    1561. Maximum Number of Coins You Can Get
    1558. Minimum Numbers of Function Calls to Make Target Array
    1557. Minimum Number of Vertices to Reach All Nodes
  • 原文地址:https://www.cnblogs.com/libolun/p/13359614.html
Copyright © 2011-2022 走看看