当我们要在列表, 字典, 集合中筛选数据,如何更优雅地在列表, 字典, 集合中筛选数据

通常我们在列表、字典或集合等容器类型中进行条件筛选时,都是使用遍历+判断的方式来实现。这种实现方式的实现逻辑非常简单,但实现的效率却比较低,代码写起来也比较麻烦。我们来看下面这个例子,筛选出列表d中小于0的数:

本期小编推送2021初学者一定会用到的Python资料,含有小编自己呕心沥血整理的免费书籍/视频/在线文档和编辑器/源代码,关于Python的安装qun:850973621

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]取出字典元素的值来进行运算。

综上,在进行列表、字典或集合等容器类型数据结构的简单元素筛选操作时,我们完全不需要呆板地利用循环遍历+判断的方式来写代码实现,毕竟那一点都不Pythonic。Python一向是优雅、高效、简洁的代名词,所以多了解一些更简洁的Pythonic式的用法是很有必要的。写Python是不担心脱发问题的,但前提得是你的代码要足够优雅和简洁,否则,老是想着用Java的方式来解决Python的问题,那神仙都帮不了你了。

原文链接:https://juejin.cn/post/6844904200434876429

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值