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
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。