通过二分查找实现抽奖活动
一、项目背景
最近开始找工作了,重新梳理一下之前做的抽奖活动项目; 1、 后台设置好奖品信息以及奖品概率; 2、 然后对奖品进行排序,比如奖品1:'电动车' 34 奖品2:'毛巾一条', 18,奖品3:'面粉一袋', 20 奖品4:'肥皂一块', 12 奖品5:'自行车', 15 奖品6: '奔驰车', 1 3、 按照奖品1 奖品2 奖品3 奖品4 奖品5 奖品6 这种顺序进行依次入库,这样是保证前端生成抽奖页面时,奖品是按照我们的奖品顺序进行顺时针填充信息; 4、 当前端抽奖页面抽奖按钮时,异步请求后端获取到奖品,然后进行页面展示;
二、后端功能代码
#!/usr/bin/env python # -*- coding:utf-8 -*- # Author:supery import bisect, random class WeightRandom: def __init__(self, items): print('数据库取出的格式化的奖品信息:', items) items.sort(key=self.prize_sort) print('快排之后的奖品信息: ', items) weights = [w for _, w in items] print('概率作为权重:',weights) self.prize = [x for x, _ in items] self.total = sum(weights) self.acc = list(self.accumulate(weights)) def accumulate(self, weights): # 累和.如accumulate([10,40,50])->[10,50,100] cur = 0 for w in weights: cur = cur + w print('累加:',cur) yield cur def prize_sort(self,elem): return elem[1] def __call__(self): rn = random.uniform(0, self.total) ran = bisect.bisect_right(self.acc, rn) print('随机生成的浮点数: ',rn,) print('索引位置: ',ran,) return self.prize[ran] def takeSecond(elem): return elem[1] if __name__ == '__main__': """ [ (奖品, 概率), (奖品, 概率), (奖品, 概率), (奖品, 概率), ] """ wr = WeightRandom([ ('电动车', 34), ('毛巾一条', 18), ('面粉一袋', 20), ('肥皂一块',12 ), ('自行车', 15), ('奔驰车', 1), ]) print('累加之后的权重列表: ',wr.acc) print('权重对应的奖品信息: ',wr.prize) print('获得的奖品获奖: 【%s】'%wr.__call__())
三、执行结果
C:\Python3\python.exe D:/xxx.py 数据库取出的格式化的奖品信息: [('电动车', 34), ('毛巾一条', 18), ('面粉一袋', 20), ('肥皂一块', 12), ('自行车', 15), ('奔驰车', 1)] 快排之后的奖品信息: [('奔驰车', 1), ('肥皂一块', 12), ('自行车', 15), ('毛巾一条', 18), ('面粉一袋', 20), ('电动车', 34)] 概率作为权重: [1, 12, 15, 18, 20, 34] 累加: 1 累加: 13 累加: 28 累加: 46 累加: 66 累加: 100 累加之后的权重列表: [1, 13, 28, 46, 66, 100] 权重对应的奖品信息: ['奔驰车', '肥皂一块', '自行车', '毛巾一条', '面粉一袋', '电动车'] 随机生成的浮点数: 88.83932955637896 索引位置: 5 获得的奖品获奖: 【电动车】 Process finished with exit code 0
四、代码说明
1. 首先从数据库获取到该活动的所有奖品信息,将奖品名称作为元组一个元素,奖励概率作为元组第二个元素; 2. 之后通过sort进行元组排序,从小到大进行排序,这样后续进行累加权重奖品概率最小的一定是在第一位,概率越大的奖品排列越靠后; 3. 通过列表表达式,分别获取到奖品名称和奖品概率,生成奖品列表和权重列表; 4. 通过迭代器累和将奖品的概率进行累加生成一个列表,默认值为0 比如accumulate([10,40,50])->[10,50,100] 0+10=10 10+40=50 50+50=100 这样是保证随机生成一个浮点数时一定是在权限累和列表中; 5. 然后通过random uniform方法随机生成一个浮点数,范围是0~100随机不包含100 6. 最后通过二分查找将将累和列表作为查询列表,浮点数作为比较的值,从右往左依次进行比较,浮点数小于右侧的数值时则返回其索引位置; 7. 获取到索引在奖品列表中进行查找奖品名称,整个抽奖过程完成!