class RedEnvelopeError(ValueError):
"""
红包赋值错误
"""
class RedEnvelope:
def __init__(self, name=None):
self.name = 'red_envelope:{}'.format(uuid.uuid1().hex) if name is None else name
def generate(self, total_amount=10000, count=10, min_amount=100, max_amount=20000, shuffle=False, unique=True):
"""
:param total_amount: 红包总金额,单位为分
:param count: 红包总个数
:param min_amount: 最小红包金额,单位为分,不可小于100,默认100
:param max_amount: 最大红包金额,单位为分,不可大于20000,默认20000
:param shuffle: 打乱顺序
:param unique: 是否可重复领取
"""
remain_amount = total_amount - count * min_amount
if count == 0 or max_amount < min_amount or remain_amount < 0:
raise RedEnvelopeError
red_envelopes = []
for remain_count in range(count, 0, -1):
if remain_count == 1:
last_amount = min(max_amount, total_amount - sum(red_envelopes))
red_envelopes.append(last_amount)
break
amount = random.random() * (remain_amount * 2 / remain_count)
if remain_amount <= amount:
amount = 0
amount = min(max_amount - min_amount, amount)
remain_amount -= amount
amount = int(amount + min_amount)
red_envelopes.append(amount)
if shuffle:
random.shuffle(red_envelopes)
为了保证不会出现领取的红包比0还小的情况,也就是说要保证每个人都能至少领到min_amount大小的红包,所以只对排除“低保”后的金额remain_amount做随机。
针对最后一个红包,要把所有剩余的金额全拿走,防止剩余。
实际分配的金额amount既不能比剩余金额remain_amount大,也不能超过max_amount - min_amount。
参考:
微信红包的随机算法是怎样实现的?
陈鹏先生的代码大致意思是这样的:假设有100元钱,分给十个人。那么第一个人获得红包大小怎么计算呢?100/10 = 10元。这是期望值。从0.01到20的区间中(其中20=10乘以2)随机抽取一个数,就是第一个人获得红包的大小。假设第一个人获得了15元,那么剩下的85元平均分给9个人,这九个人平均获得红包大小为9.4元,那么第二个人的红包大小均匀分布于0.01元到18.80元的区间中,依次类推。算法保证最后一个人至少抽到0.01元。
作者:Mr.L
链接:https://www.zhihu.com/question/22625187/answer/85431684
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。