zoukankan      html  css  js  c++  java
  • Python 拓展之推导式

    写在之前

    推导式是从一个或多个迭代器快速简洁的创建数据结构的一种办法,它可以将循环和条件判断结合,从而可以避免语法冗长的代码。

    列表推导式

    我在之前的文章中(零基础学习 Python 之 for 循环语句)写过列表推导式,但是写的相对简单,今天我准备再详细说一下,会的权当复习,不会的正好学习。

    如果让你创建一个从 0 到 5 的整数列表,按照我们之前学过的方法,你可以这样:

    >>> my_list = []
    >>> my_list.append(0)
    >>> my_list.append(1)
    >>> my_list.append(2)
    >>> my_list.append(3)
    >>> my_list.append(4)
    >>> my_list.append(5)
    >>> my_list
    [0, 1, 2, 3, 4, 5]
    

    如果用我们前天学过的 for 循环,你可以这样:

    >>> my_list = []
    >>> for i in range(0,6):
    ...     my_list.append(i)
    ... 
    >>> my_list
    [0, 1, 2, 3, 4, 5]
    

    上面的两个方法都是可行的 Python 方法,得到的都是相同的结果,但是这都不是最像 Python 风格的创建列表的方式,什么是 Python 风格?当然是简洁优雅!请看下面:

    >>> my_list = [i for i in range(0,6)]
    >>> my_list
    [0, 1, 2, 3, 4, 5]
    

    看完这种方法,再比较之前的那两种方法,列表推导的优点一目了然。

    在第一行中,第一个变量 i 为列表的生成值,换句话说,就是将循环的结果放在列表 my_list 中,第二个 i 是循环变量,这里要提一点的是,第一个变量 i 可以是表达式,请看下面的例子:

    >>> my_list = [i*i for i in range(0,6)]
    >>> my_list
    

    除了上面第一个变量可以是表达式以外,列表推导式也可以加上条件表达式,请看下面的例子:

    >>> my_list = [i for i in range(0,6) if i  % 2 == 1]
    >>> my_list
    [1, 3, 5]
    

    上述的例子通过列表推导式得到一个 0 到 5 之间的奇数列表,是不是要比传统的方法简洁很多呢?所以,现在你是不是该动动手指写一个传统的求奇数列表的例子来对比对比呢?

    上面我们用的一直是一个 for 循环的例子,那如果是双层 for 循环呢?

    >>> first = range(1,4)
    >>> second = range(7,9)
    >>> for i in first:
    ...    for j in second:
    ...            print(i,j)
    ... 
    1 7
    1 8
    2 7
    2 8
    3 7
    3 8
    

    如果是上面这个例子,你该怎么用列表推导式呢?如果你思考完,请看下面的答案:

    >>> first = range(1,4)
    >>> second = range(7,9)
    >>> results = [(i,j) for i in first for j in second]
    >>> for result in results:
    ...     print(result)
    ... 
    (1, 7)
    (1, 8)
    (2, 7)
    (2, 8)
    (3, 7)
    

    我在这将上面的例子用了元组输出,具体用什么形式,看当时的情况和自己的心情。

    字典推导式

    除了列表,字典其实也有自己的推导式,它和列表推导式其实有些相似,也有 if 条件判断以及多个 for 循环的迭代语句,下面举个最简单的例子:

    >>> words = 'rocky like python'
    >>> letter_cnt = {letter:words.count(letter) for letter in words}
    >>> letter_cnt
    {'r': 1, 'o': 2, 'c': 1, 'k': 2, 'y': 2, ' ': 2, 'l': 1, 'i': 1, 'e': 1, 'p': 1, 't': 1, 'h': 1, 'n': 1}
    

    上面的例子是计算句子里每个字母出现的个数,但是不知道你有没有发现,有些重复的字母的次数出现了多次?还记得怎么解决掉字符串里重复的字母么?是 set 啊,快点动手试试吧。

    集合推导式

    集合也不例外,也有自己的推导式,也是跟上面的列表推导式和字典推导式类似,不只是在简单的,或者是带条件判断的都是如此,请看下面的例子:

    >>> my_set = {i for i in range(0,6) if i % 3 == 1}
    >>> my_set
    {1, 4}
    

    生成器推导式

    我们说了三个,是不是掉了什么?对,是存在感最不强的元组,那么元组推导式是什么样子的呢?你肯定想说:“简单!不就是把列表推导式的方括号变成圆括号不就得了么?!”,其实我想告诉你的事,确实有圆括号的推导式,但不是元组的,因为元组没有推导式!圆括号的那个推导式是生成器推导式,不信的话请看下面的例子:

    >>> my_exp = (i for i in range(0,6))
    >>> my_exp
    <generator object <genexpr> at 0x110090308>
    >>> type(my_exp)
    <class ‘generator'>
    

    你现在只需要知道生成器是将数据传给迭代器的一种方式就好了,至于生成器我在之后的文章中会详细讲到,尽情期待。

    虽然我们还没学生成器这个概念,但是不妨碍我们学习这个推导式,你可以直接对生成器的对象进行迭代,比如像下面一样:

    >>> for exp in my_exp:
    ...    print(exp)
    ... 
    0
    1
    2
    3
    4
    5
    

    作为一个每个知识点都想写的人来说,这里劳烦大家再记住一点的是,一个生成器只能生成一次,如果想再生成一次的话,你会发现它消失掉了,什么意思呢,看下面的例子:

    >>> second_exp = list(my_exp)
    >>> second_exp
    []
    

    现在生成器先记住这些就可以,记不住也没关系,我还会细讲生成器,我们到时候再讨论。

    写在最后

    更多内容,欢迎关注公众号「Python空间」,期待和你的交流。

  • 相关阅读:
    POJ 1426 Find The Multiple(数论——中国同余定理)
    POJ 2253 Frogger(Dijkstra变形——最短路径最大权值)
    POJ 3790 最短路径问题(Dijkstra变形——最短路径双重最小权值)
    POJ 3278 Catch That Cow(模板——BFS)
    HDU 1071 The area
    HDU 1213 How Many Tables(模板——并查集)
    POJ 1611 The Suspects
    light oj 1214 Large Division
    POJ 1258 Agri-Net(Prim算法求解MST)
    POJ 2387 Til the Cows Come Home(模板——Dijkstra算法)
  • 原文地址:https://www.cnblogs.com/Rocky0429/p/10103158.html
Copyright © 2011-2022 走看看