python 的推导式是一种独特的数据处理方式,可以从一个数据序列构建另一个数据序列的结构体。Python 推导式是一种强大且简洁的语法,适用于生成列表、字典、集合和生成器。在使用推导式时,需要注意可读性,尽量保持表达式干净简洁,以免影响代码的可读性和可维护性。Python 支持各种数据结构的推导式:
- 列表(list)推导式
- 字典(dict)推导式
- 集合(set)推导式
- 元组(tuple)推导式
列表推导式
列表推导式的格式如下
1 | [表达式 for 变量 in 列表] |
其中,各个值含义如下:
- out_exp_res:列表生成元素表达式,可以是有返回值的函数。
- for out_exp in input_list:迭代 input_list 将 out_exp 传入到 out_exp_res 表达式中。
- if condition:条件语句,可以过滤列表中不符合条件的值。
如下代码可以筛选出原序列中可以被 3 整除的数
1 | raw_list = [5,6,7,8,9,0,1,2,3,4,5] |
如下代码可以筛选出原序列中长度大于 3 的字符串
1 | raw_list = ['hcw','your','sn','asdasf'] |
字典推导式
字典推导基本格式:
1 | { key_expr: value_expr for value in collection } |
使用示例如下:
1 | listdemo = ['Google','Runoob', 'Taobao'] |
集合推导式
集合推导式基本形式如下:
1 | { expression for item in Sequence } |
比如可以使用如下代码来实现一个 x^2 的集合
1 | setnew = {i**2 for i in range(1,6)} |
元组推导式
元组推导式可以利用 range 区间、元组、列表、字典和集合等数据类型,快速生成一个满足指定需求的元组。其基本格式如下:
1 | (expression for item in Sequence ) |
元组推导式和列表推导式的用法也完全相同,只是元组推导式是用 () 圆括号将各部分括起来,而列表推导式用的是中括号 [],另外元组推导式返回的结果是一个生成器对象。最后使用 tuple 函数,可以直接将生成器对象转换成元组。
迭代器
迭代是 Python 最强大的功能之一,是访问集合元素的一种方式。
迭代器是一个可以记住遍历的位置的对象。
迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
迭代器有两个基本的方法:iter() 和 next()。
字符串,列表或元组对象都可用于创建迭代器:
1 | testlist = [1,2,3,4] |
运行如上程序,会输出 1、2、3、4。迭代器对象还可以使用常规for语句进行遍历,如下代码也会输出 1 2 3 4 。
1 | testlist = [1,2,3,4] |
把一个类作为一个迭代器使用需要在类中实现两个方法 __iter__() 与 __next__() 。Python 中类的构造函数为 __init()__,它会在对象初始化的时候执行。
__iter__() 方法返回一个特殊的迭代器对象, 这个迭代器对象实现了 next() 方法并通过 StopIteration 异常标识迭代的完成。
__next__() 方法会返回下一个迭代器对象。
如下代码创建一个返回数字的迭代器,初始值为 1,逐步递增 1。
1 | class Mynumbers: |
StopIteration 异常用于标识迭代的完成,防止出现无限循环的情况,在 __next__() 方法中我们可以设置在完成指定循环次数后触发 StopIteration 异常来结束迭代。
1 | class Mynumbers: |
生成器
在 Python 中,使用了 yield 的函数被称为生成器(generator)。
yield 是一个关键字,用于定义生成器函数,生成器函数是一种特殊的函数,可以在迭代过程中逐步产生值,而不是一次性返回所有结果。
跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。
当在生成器函数中使用 yield 语句时,函数的执行将会暂停,并将 yield 后面的表达式作为当前迭代的值返回。
然后,每次调用生成器的 next() 方法或使用 for 循环进行迭代时,函数会从上次暂停的地方继续执行,直到再次遇到 yield 语句。这样,生成器函数可以逐步产生值,而不需要一次性计算并返回所有结果。
调用一个生成器函数,返回的是一个迭代器对象。
下面是一个简单的示例,展示了生成器函数的使用:
1 | def countdown(n): |
以上实例中,countdown 函数是一个生成器函数。它使用 yield 语句逐步产生从 n 到 1 的倒数数字。在每次调用 yield 语句时,函数会返回当前的倒数值,并在下一次调用时从上次暂停的地方继续执行。
通过创建生成器对象并使用 next() 函数或 for 循环迭代生成器,我们可以逐步获取生成器函数产生的值。在这个例子中,我们首先使用 next() 函数获取前三个倒数值,然后通过 for 循环获取剩下的两个倒数值。
生成器函数的优势是它们可以按需生成值,避免一次性生成大量数据并占用大量内存。此外,生成器还可以与其他迭代工具(如for循环)无缝配合使用,提供简洁和高效的迭代方式。
如下代码石使用 yield 实现斐波那契数列
1 | def fibonacci(n): |
做题
力扣 2105.给植物浇水
Alice 和 Bob 打算给花园里的 n 株植物浇水。植物排成一行,从左到右进行标记,编号从 0 到 n - 1 。其中,第 i 株植物的位置是 x = i 。
每一株植物都需要浇特定量的水。Alice 和 Bob 每人有一个水罐,最初是满的 。他们按下面描述的方式完成浇水:
- Alice 按 从左到右 的顺序给植物浇水,从植物 0 开始。Bob 按 从右到左 的顺序给植物浇水,从植物 n - 1 开始。他们 同时 给植物浇水。
- 无论需要多少水,为每株植物浇水所需的时间都是相同的。
- 如果 Alice/Bob 水罐中的水足以 完全 灌溉植物,他们 必须 给植物浇水。否则,他们 首先(立即)重新装满罐子,然后给植物浇水。
- 如果 Alice 和 Bob 到达同一株植物,那么当前水罐中水 更多 的人会给这株植物浇水。如果他俩水量相同,那么 Alice 会给这株植物浇水。
给你一个下标从 0 开始的整数数组 plants ,数组由 n 个整数组成。其中,plants[i] 为第 i 株植物需要的水量。另有两个整数 capacityA 和 capacityB 分别表示 Alice 和 Bob 水罐的容量。返回两人浇灌所有植物过程中重新灌满水罐的 次数 。
答案
想法很简单,使用暴力模拟,使用两个 index 去从左到右和从右到左遍历数组,写下如下代码,顺利通过,并且来到了时间复杂度为 O(n) 的最优解。
1 | class Solution: |