Python trick:filter—序列滤波

1. 问题场景

删除列表中的正数部分

my_list = [i for i in range(10)]
for it in my_list:
    if it>0:
        my_list.remove(it)
print(my_list)
out: [0, 2, 4, 6, 8]
2. 问题分析

for … in 遍历中,是利用下标遍历的,这个下标从开始就固定了:0~9
而随着remove,会造成list内元素的自动补位,从而在遍历过程中漏掉了被删元素的下一个元素

3. 解决方案

两种解决方案:使用filter函数滤波,或者倒序遍历进行删除(del或remove)
(注意,python3中filter返回一个迭代器,因此需要强制转换为list)
源码如下:

from time import time
# 初始化
length = 10000
my_list1 = [i for i in range(length)]
my_list2 = [i for i in range(length)]
my_list3 = [i for i in range(length)]
# 方法一
time1 = time()
my_list1 = list(filter(lambda x: x<=0, my_list1))
time2 = time()
# 方法二
for i in range(len(my_list2)-1, -1, -1):
    if my_list2[i]>0:
        del(my_list2[i])
time3 = time()
# 方法三
for i in range(len(my_list3)-1, -1, -1):
    if my_list3[i]>0:
        my_list3.remove(my_list3[i])
time4 = time()
# 性能评估
print("列表维度:"+str(length))
print("方法一用时:"+str(round(time2-time1,5)))
print("方法二用时:"+str(round(time3-time2,5)))
print("方法三用时:"+str(round(time4-time3,5)))
4. 性能评估

(单位:秒)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5. 进阶

filter也能够处理字典等序列,比如下面这个场景:

a 是由四个字典组成的列表

a = [
    {'id':1, 'w':1, 'h':1},
    {'id':1, 'w':2, 'h':2},
    {'id':2, 'w':3, 'h':3},
    {'id':2, 'w':4, 'h':4},
    ]

需求:仅保留’id’==1的两个字典,且删除其中的’id’键值对应的项,即期望输出为:

a = [
    {'w':1, 'h':1},
    {'w':2, 'h':2},
    ]

方法:使用两次 filter 进行滤波,第一次过滤‘id’==1的内容,第二次去除字典中键值为’id’的项

a = [
    {'id':1, 'w':1, 'h':1},
    {'id':1, 'w':2, 'h':2},
    {'id':2, 'w':3, 'h':3},
    {'id':2, 'w':4, 'h':4},
    ]
b = [dict(
        filter(lambda y: y[0]!='id', x.items())
    ) 
     for x in 
        filter(lambda x: x['id']==1, a)]
print(b)

[Out][{'w': 1, 'h': 1}, {'w': 2, 'h': 2}]
6. 惰性运算

需要注意的是,使用filter返回的对象,只可以访问一次,如下面两个例子:

a = [1,2,3,4,5]
f = filter(lambda x: x>2, a)
print(f)
print(list(f))
print(f)
print(list(f))

[Out]<filter object at 0x000001DB7EF8BE48>
[3, 4, 5]
<filter object at 0x000001DB7EF8BE48>
[]
a = [1,2,3,4,5]
f = filter(lambda x: x>2, a)
print('第一次访问:')
for i in f:
    print(i)
print('第二次访问:')
for i in f:
    print(i)
    
[Out]:
第一次访问:
3
4
5
第二次访问:

可以发现,不论是转成list,还是直接访问,都只能操作一次~这是由于 filter 产生的迭代器使用了“惰性运算”,它仅供迭代一次,也就是它只有被使用的时候才被取出或计算出,放到内存中,访问之后随即销毁。这可以提升性能,节约内存。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值