d = [-1, 10, -2, 3, 4, 7, -9] result = [] for num in d: if num < 0: result.append(num) print(result) # 结果:[-1, -2, -9]
这里,我们首先用了一个for循环,然后又用了一个if判断对每一个数进行判断,最终才得到符合条件的结果。Python一向追求代码简洁、优美、高效,那有没有更加简单的方法可以实现这个需求呢?答案其实有的,我们可以利用更加Pythonic的方式来解决这个问题。
在Python中,我们有一个叫列表推导式的东西,相信很多了解Python的人应该都知道。除了列表推导式,当然还有字典推导式、元组推导式、集合推导式等。推导式的表示法非常简洁,并且Python在其内部已经对算法进行了大量的优化,所以推导式运行起来比单纯的循环要快很多,并且语法也更加优雅。那么,接下来我们可以尝试使用列表推导式来求实现上面的那个效果。代码如下:
d = [-1, 10, -2, 3, 4, 7, -9] result = [x for x in d if x < 0] print(result) # 结果:[-1, -2, -9]
核心的代码缩短到了只有一行就搞定了,效率非常高。至于运行效率,为了看到效果,我们可以使用一个稍微大一点的列表做个试验,比如利用random生成1000000个-10到10之间的随机数,代码如下:
import random import time d = [random.randint(-10, 10) for _ in range(1000000)] result = [] start = time.time() for num in d: if num < 0: result.append(num) print('运行时间为:', time.time()-start) # 运行时间约为0.15秒左右
如果用列表推导式来实现,代码如下:
import random import time d = [random.randint(-10, 10) for _ in range(1000000)] start = time.time() result = [x for x in d if x < 0] print('运行时间为:', time.time()-start) # 运行时间约为0.05秒左右
可见,列表推导式无论从编写代码的效率还是运行效率上,都更胜一筹。
除了列表推导式,还有字典推导式也是同样的道理。我们也来看看如何通过字典推导式来实现字典中特定元素的过滤。假如我们现在有一个学生成绩的字典,里面有20个学生的成绩信息,要求用字典推导式筛选出所有分数在90分以上的学生,我们的代码就可以这样写:
import random d = {'student{}'.format(i): random.randint(60, 100) for i in range(1, 21)} result = {k: v for k, v in d.items() if v > 90} print(result)
除了推导式之外,Python内置的filter函数也是专门用来筛选容器类型的数据结构里的元素的。通常我们在使用filter函数的时候,需要传两个参数,一个用于筛选元素的函数指针,一般我们会定义一个lambda匿名函数。另一个参数是被筛选的容器对象,比如一个字典或一个列表。另外还要注意一点就是,在Python3中,filter函数返回的是一个生成器对象,如果想要得到一个列表或者是字典,必须做一次强制转换。
接下来,我们以列表为例,用filter来实现第一个列表推导式筛选元素的例子,代码就应该这样来写:
d = [random.randint(-10, 10) for _ in range(20)] result = list(filter(lambda x: x < 0, d)) print(result)
上面的代码运行结果跟前面使用列表推导式是一模一样的,但filter的运行效率没有列表推导式高。另外,再次强调一下,filter中提供的第一个参数是一个函数指针,我们一般会直接定义一个lambda表达式。对于这个lambda表达式有两点必须注意,一是它必须返回一个布尔值作为结果,凡是结果为True的,就是要留下的,结果为False的就是要被筛掉的。二是这里的lambda表达式只接受一个参数(lambda本身是可以接收多个参数的,但这里只能接收一个)。那么这个参数是怎么来的呢,是谁提供的呢?答案是这个参数将由filter函数的第二个参数,也就是那个容器对象自动提供,所以每次比较的值就是容器对象内的一个元素,以实现依次比较的目的。
明白了这些问题之后,要实现利用filter函数来实现字典元素的筛选,也是很容易的一件事了,代码如下:
import random d = {'student{}'.format(i): random.randint(60, 100) for i in range(1, 21)} result = dict(filter(lambda item: item[1] > 90, d.items())) print(result)
上面的代码中,lambda里面的item为什么要取item[1]呢?因为前面我们说过,lambda只接收一个参数,所以字典中的元素的键和值是以一个整体的形式来传入的。而我们要比较的是值,所以就要通过item[1]取出字典元素的值来进行运算。
欢迎关注我的公众号,学习更多优质内容!