通过二分查找实现抽奖活动

一、项目背景

最近开始找工作了,重新梳理一下之前做的抽奖活动项目;
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:Python3python.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. 获取到索引在奖品列表中进行查找奖品名称,整个抽奖过程完成!

  

原文地址:https://www.cnblogs.com/supery007/p/10883495.html