视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
python实现红包裂变算法
2020-11-27 14:35:21 责编:小采
文档
本文实例介绍了python实现红包裂变算法,分享给大家供大家参考,具体内容如下

Python语言库函数
安装:pip install redpackets
使用:

import redpackets
 
redpackets.split(total, num, min=0.01)

1、前情提要
过年期间支付宝红包、微信红包成了全民焦点,虽然大多数的红包就一块八角的样子,还是搞得大家乐此不疲。作为一名程序猿,自然会想了解下红包的实现细节,微信目前是没有公布红包的实现细节的,所以这里就综合网上的讨论通过 Python 来实现红包裂变。
2、红包规则

红包领了不少,据观察红包主要有以下几个条件:
所有人都能分到红包,也就是不会出现红包数值为 0 的情况
所有人的红包数值加起来等于支付的金额
红包波动范围比较大,约 5%~8% 的红包数值在平均值的两倍以上,同时数额 0.01 出现的概率比较高
红包的数值是随机的,并且数值的分布近似于正态分布
其中,前两条是最基本的条件,如果要求不是特别高,可以完全只考虑前两个条件即可。
3、裂变方式一
3.1、简单实现

def weixin_divide_hongbao(money, n):
 divide_table = [random.randint(1, 10000) for x in xrange(0, n)]
 sum_ = sum(divide_table)
 return [x*money/sum_ for x in divide_table]

3.2、相关问题
如使用该方式,需要自己去添加相关代码逻辑去处理如下问题
浮点数精度问题
边界值的处理

4、裂变方式二
4.1、完整实现

# -*- coding: utf-8 -*-
 
from decimal import Decimal, InvalidOperation
 
import random
 
 
def money_val(min, max):
 return min if min > max else Decimal(str(random.randint(min, max)))
 
 
def money_random(total, num, min=0.01):
 """
 :param total=10; # 红包总额 10 元
 :param num=8; # 分成 8 个红包,支持 8 人随机领取
 :param min=0.01; # 每个人最少能收到 0.01 元
 """
 money_list = []
 
 try:
 total = Decimal(str(total))
 except InvalidOperation as e:
 return money_list, e.message
 
 try:
 if isinstance(num, float) and int(num) != num:
 raise ValueError(u'Invalid value for Num: \'{0}\''.format(num))
 num = Decimal(str(int(num)))
 except ValueError as e:
 return money_list, e.message
 
 try:
 min = Decimal(str(min))
 except InvalidOperation as e:
 return money_list, e.message
 
 if total < num * min:
 return money_list, u'Invalid value for Total-{0}, Num-{1}, Min-{2}'.format(total, num, min)
 
 for i in xrange(1, num):
 safe_total = (total - (num - i) * min) / (num - i) # 随机安全上限
 money = money_val(min * 100, int(safe_total * 100)) / 100
 total -= money
 money_list.append(money)
 money_list.append(total)
 
 random.shuffle(money_list) # 随机打乱
 
 return money_list, u'Success'
 
 
if __name__ == '__main__':
 print money_random(1, 10)
 print money_random(0.1, 10)
 print money_random(0.11, 10)
 print money_random(0.12, 10)

4.2、函数使用
4.2.1、使用 money_random 预先将红包裂变,存放在 memcache 或者 redis 中

  • total —— 红包总额
  • num —— 裂变个数
  • min —— 非必须,红包最小面额,默认 0.01
  • 4.2.2、当用户抢红包的时候,直接 pop 出来一个,直到将所有红包 pop 完
    4.3、库使用说明
    因为涉及到浮点运算,所以使用了 Decimal
    5、源码示例
    5.1、运行

    python algorithm_utils.py
    

    5.2、效果
    5.2.1、对于如下几个示例

    if __name__ == '__main__':
     print money_random(1, 10)
     print
     print money_random(0.1, 10)
     print
     print money_random(0.11, 10)
     print
     print money_random(0.12, 10)
     print
    

    5.2.2、裂变后的红包列表如下

    下载本文
    显示全文
    专题