zoukankan      html  css  js  c++  java
  • python 循环高级用法 [expression for x in X [if condition] for y in Y [if condition] ... for n in N [if condition] ]按照从左至右的顺序,分别是外层循环到内层循环

    高级语法

    除了像上面介绍的 [x ** 2 for x in L] 这种基本语法之外,列表推导式还有一些高级的扩展。

    4.1. 带有if语句

    我们可以在 for 语句后面跟上一个 if 判断语句,用于过滤掉那些不满足条件的结果项。

    例如,我想去除列表中所有的偶数项,保留奇数项,可以这么写:

    >>> L = [1, 2, 3, 4, 5, 6]
    >>> L = [x for x in L if x % 2 != 0]
    >>> L
    [1, 3, 5]
    

    4.2. 带有for嵌套

    在复杂一点的列表推导式中,可以嵌套有多个 for 语句。按照从左至右的顺序,分别是外层循环到内层循环。

    例如:

    >>> [x + y for x in 'ab' for y in 'jk']
    ['aj', 'ak', 'bj', 'bk']
    

    4.3. 既有if语句又有for嵌套

    列表推导式可以带任意数量的嵌套 for 循环,并且每一个 for 循环后面都有可选的 if 语句。

    通用语法:

    [ expression for x in X [if condition]
                 for y in Y [if condition]
                 ...
                 for n in N [if condition] ]
    

    例如,下面的代码输出了0~4之间的偶数和奇数的组合。

    >>> [(x, y) for x in range(5) if x % 2 == 0 for y in range(5) if y % 2 == 1]
    [(0, 1), (0, 3), (2, 1), (2, 3), (4, 1), (4, 3)]
    

    等价于下面的一般 for 循环:

    >>> L = []
    >>> for x in range(5):
    ...     if x % 2 == 0:
    ...         for y in range(5):
    ...             if y % 2 == 1:
    ...                 L.append((x, y))
    >>> L
    [(0, 1), (0, 3), (2, 1), (2, 3), (4, 1), (4, 3)]
    

    4.4. 列表推导式生成矩阵

    生成矩阵的方式有多种,例如手动赋值、一般for循环,还有就是列表推导式。如果我们要用列表推导式生成下面的矩阵,可以怎么写?

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

    一种方法是:

    >>> M = [[x, x+1, x+2] for x in [1, 4, 7]]
    >>> M
    [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
    

    矩阵的列数少时可以使用这种方法。

    如果矩阵的列数较多,我们可以使用另外一种方式:在循环变量的表达式中使用列表推导式。

    具体代码如下:

    >>> M = [[y for y in range(x, x+3)] for x in [1, 4, 7]]
    >>> M
    [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
    

    与之前带 for 嵌套的语法不同,这个例子中,实际使用的是最基本的 [expression for x in L] 语法,只有一个 for 语句。

    复杂的地方在于前面的变量表达式 expression 不再是简单的变量运算,而是一个列表推导式,在这个例子中就是 [y for y in range(x, x+3)]
    内层的列表推导式返回一个行向量,而这些行向量经由外层的列表推导式,最终形成一个二维列表,也就是我们想要的矩阵。

    当然,在实际的应用中不能单纯追求代码的简洁,还要考虑到代码的可读性和维护成本。
    如果代码变得过于复杂,不易于理解,我们宁可多写几行代码来增加它的可读性。

    5. 生成器表达式

    生成器表达式与列表推导式的语法相同,区别在于生成器表达式的外面使用圆括号,而列表推导式使用方括号。

    有关生成器的介绍,请参考这篇文章:《Python高级编程之初识生成器》

    6. 集合推导式和字典推导式

    注意:集合推导式和字典推导式只有在Python2.7以及之后的版本中才有,Python2.7之前的版本不支持这两种推导式。

    集合推导式的语法与列表推导式相同,只需要把外面的方括号改成花括号即可。

    例如,我们可以通过以下方式来生成一个集合:

    >>> {x ** 2 for x in [1, 2, 2]}
    {1, 4}
    

    字典推导式的外面也是使用花括号,不过花括号的内部需要包含键值两部分。

    在值不重复的情况下,我们可以通过字典推导式快速交换键值对:

    >>> D = {'a':1, 'b':2, 'c':3}
    >>> D = {value: key for key, value in D.items()}
    >>> D
    {1: 'a', 2: 'b', 3: 'c'}
    

    lix = []; for x in range(1, 101): lix.push(x ** 2) 执行结果:lix = [1,4,9,16,25.....]
    在列表构建器的表达式中,可以添加简单的条件处理
    lix = [x * x for x in range(1, 101) if x % 2 == 0]
    执行结果:lix = [4,16,36.....]
    

    也可以在循环过程中,来使用多层循环嵌套,实现更加复杂的效果

    lix = [x + y  for x in "abc" for y in "xyz"]
    执行结果:['ax', 'ay', 'az', 'bx', 'by', 'bz', 'cx', 'cy', 'cz']
    

    列表动态构建器

    但是我们通过前面的学习已经知道,这些数据都是加载到内存中的,如果列表中的数据量比较大的情况下,内存消耗是比较严重的
    在某些情况下,我们只需要使用列表中的一部分数据,后面的数据并不是特别关心,如:通过列表来记录一个符合某种规则的序列,每次我们只是关心下一个数据,并不关心后面的N条数据,应该怎么做呢?比如我们需要一个奇数列表

    # 常规构建器的做法
    lix = [2*x + 1 for x in range(1, 101)]
    # 执行结果:[1,3,5,7,9,11,13,15,17.....]
    # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    # 常规构建器可以直接构建生成
    # 但是存在问题,如果一次构建的数据量太大,会严重占用内存
    # 我们在使用该列表的时候,有可能只是使用前10项
    # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    # 使用列表动态构建器
    lix = (2 * x - 1 for x in range(1, 101))
    # 执行结果:print (lix) --> <generator object <genexpr> at 0x7f232e462048>
    next(lix)
    # 执行结果:1
    next(lix)
    # 执行结果:3
    next(lix)
    # 执行结果:5
    next(lix)
    # 执行结果:7
    # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    # 列表动态构建器
    # 和构建器基本没有区别,创建的时候列表中是没有数据的
    # 必须通过next()函数来获取列表中的下一条数据
    # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    

    from:https://www.jianshu.com/p/fa3fda487f15
     
     

    []改成(),就创建了一个generator:

    >>> L = [x * x for x in range(10)]
    >>> L
    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    >>> g = (x * x for x in range(10))
    >>> g
    <generator object <genexpr> at 0x1022ef630>
    

    L和g的区别仅在于最外层的[]()L是一个list,而g是一个generator。

    如果要一个一个打印出来,可以通过next()函数获得generator的下一个返回值:

    >>> next(g)
    0
    >>> next(g)
    1
    >>> next(g)
    4
    >>> next(g)
    9
    >>> next(g)

    next(g)实在是太变态了,正确的方法是使用for循环,因为generator也是可迭代对象:

    >>> g = (x * x for x in range(10))
    >>> for n in g:
    ...     print(n)
    ... 
    0
    1
    4
    9
    要把fib函数变成generator,只需要把print(b)改为yield b就可以了:
    def fib(max):
        n, a, b = 0, 0, 1
        while n < max:
            yield b
            a, b = b, a + b
            n = n + 1
        return 'done'
    

    yield关键字,那么这个函数就不再是一个普通函数,而是一个generator:

    >>> f = fib(6)
    >>> f
    <generator object fib at 0x104feaaa0>
    

    return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。

     
  • 相关阅读:
    [ jquery 选择器 :hidden ] 此方法选取匹配所有不可见元素,或者type为hidden的元素
    剑指 Offer 03. 数组中重复的数字 哈希
    LeetCode 1736. 替换隐藏数字得到的最晚时间 贪心
    Leetcode 1552. 两球之间的磁力 二分
    Leetcode 88. 合并两个有序数组 双指针
    LeetCode 1744. 你能在你最喜欢的那天吃到你最喜欢的糖果吗?
    LeetCode 1743. 相邻元素对还原数组 哈希
    LeetCode 1745. 回文串分割 IV dp
    剑指 Offer 47. 礼物的最大价值 dp
    剑指 Offer 33. 二叉搜索树的后序遍历序列 树的遍历
  • 原文地址:https://www.cnblogs.com/bonelee/p/8545263.html
Copyright © 2011-2022 走看看