需求說明
以前很討厭點外賣的我,最近中午經常點外賣,因為確實很方便,提前點好餐,算準時間,就可以在下班的時候吃上飯,然后省下的那些時間就可以在中午的時候多休息一下了。
點餐結束后,會有一個好友分享紅包功能,雖說這個紅包不能提現,但卻可以抵扣點餐費用,對于經常點餐的人來說,直接用于抵扣現金確實是很大的誘惑,在點餐之后所獲得的那個紅包,必須要分享出去才能拆。
那么如果自己也想實現以下搶紅包功能,需要說明的是,本文所描述的紅包功能更多的關注與隨機紅包的生成,至于高并發、數據一致性等問題,本文暫未涉及,以下是本文所討論的兩個技術點:
不同的消費金額獲取的紅包總額不同,消費金額越大,紅包總額就越大,紅包總數也就越多;假設有一天,有一種需求是,需要保證參與搶紅包的人獲得的紅包金額在平均數附近波動,也就是盡量的服從正態分布;
功能實現
本文描述的場景,所涉及到的金額以分為單位,目的是為了更好的處理隨機數。總體的示意圖如下:
消費后紅包的初始化
需求重點,用戶分享出去的紅包總額跟消費總額成正比,可以分拆的子紅包個數也與消費總額成正比。
比如:
10-20元的消費金額,可以分享的單個紅包金額為10元,可以供5個人搶20-40元的消費金額,可以分享的單個紅包金額為20元,可以供8個人搶40-60元的消費金額,可以分享的單個紅包金額為30元,可以供10個人搶60-100元的消費金額,可以分享的單個紅包金額為40元,可以供10個人搶100元以上的消費金額,可以分享的單個紅包金額為50元,可以供10個人搶
那么我們設計出來一個實體,用于表示紅包信息,以方便的配置及調整紅包規則
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
public class RedPacketsInfo { /// <summary> /// 最大消費金額 /// </summary> public int MaxAmount { get ; set ; } /// <summary> /// 最小消費金額 /// </summary> public int MinAmount { get ; set ; } /// <summary> /// 紅包金額 /// </summary> public int TotalAmount { get ; set ; } /// <summary> /// 紅包可被分割的數量 /// </summary> public int RedPacketQuantity { get ; set ; } } |
紅包初始化信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
private static List<RedPacketsInfo> GetRedPackets() { return new List<RedPacketsInfo>() { new RedPacketsInfo { MinAmount = 1000, MaxAmount = 2000, RedPacketQuantity = 5, TotalAmount=1000 }, new RedPacketsInfo { MinAmount = 2000, MaxAmount = 3000, RedPacketQuantity = 5, TotalAmount=1000 }, new RedPacketsInfo { MinAmount = 4000, MaxAmount = 6000, RedPacketQuantity = 5, TotalAmount=1000 }, new RedPacketsInfo { MinAmount = 6000, MaxAmount = 8000, RedPacketQuantity = 5, TotalAmount=1000 }, new RedPacketsInfo { MinAmount = 10000, MaxAmount = int .MaxValue, RedPacketQuantity = 5, TotalAmount=1000 } }; } |
接下來我們就可以通過消費金額獲取相應的紅包信息了。
隨機紅包的生成時機及處理
隨機紅包的生成可以在搶之前生成也可以在搶的過程中確定,一般而言,很多時候紅包會在搶的過程中動態的實際分配,不過在本文中,紅包在用戶分享成功后會預先生成,主要原因是為了更好地處理處理數據,以使得數據能夠服從正態分布。
以下是其流程圖,其中有一段邏輯是回調功能,可能會有圈友會問,如何保證有回調以及回調是成功的,這個地方有很多種處理,比如MQ、任務調度等,此處也不做討論
那么我們需要設計一個新的實體,以表示分享出去的紅包及其生成的隨機紅包:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
public class SharedRedPacket { / / / <summary> / / / 分享人UserId / / / < / summary> public int SenderUserId { get; set ; } / / / <summary> / / / 分享時間 / / / < / summary> public DateTime SendTime { get; set ; } public List <RobbedRedPacket> RobbedRedPackets { get; set ; } } public class RobbedRedPacket { / / / <summary> / / / 搶到紅包的人的UserId / / / < / summary> public int UserId { get; set ; } / / / <summary> / / / 搶到的紅包金額 / / / < / summary> public int Amount { get; set ; } / / / <summary> / / / 搶到時間 / / / < / summary> public DateTime RobbedTime { get; set ; } } |
在實現過程中,根據用戶消費金額獲取相應紅包,然后通過隨機數,生成n-1個原始的隨機數據,最后一個數據用總和減去n-1個數據的和獲取到
1
2
3
4
5
6
7
8
9
10
11
|
/ / 紅包隨機拆分 Random ran = new Random(); List <double> randoms = new List <double>(redPacketsList.Count); for ( int i = 0 ; i < redPacketsInfo.RedPacketQuantity - 1 ; i + + ) { int max = (totalAmount - (redPacketsInfo.RedPacketQuantity - i)) * 1 ; int result = ran. Next ( 1 , max ); randoms.Add(result); totalAmount - = result; } randoms.Add(totalAmount); |
然后通過設置好系數,以處理數據達到服從正太分布的目的:
1
2
3
4
5
6
7
|
//正太分布處理 for ( int i = 0; i < redPacketsInfo.RedPacketQuantity; i++) { double a = Math.Sqrt(Math.Abs(2 * Math.Log(randoms[i], Math.E))); double b = Math.Cos(2 * Math.PI * randoms[i]); randoms[i] = a * b * 0.3 + 1; } |
經過第二次處理后,得到的數據與原始數據有偏差,那么我們通過等比例方式再次處理,以確保拆分后的紅包總額等于紅包原始總額:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
//生成最終的紅包數據 double d = originalTotal / randoms.Sum(); SharedRedPacket sharedRedPacket = new SharedRedPacket(); sharedRedPacket.RobbedRedPackets = new List<RobbedRedPacket>(redPacketsList.Count); for ( int i = 0; i < redPacketsInfo.RedPacketQuantity - 1; i++) { sharedRedPacket.RobbedRedPackets.Add( new RobbedRedPacket { Amount = ( int )Math.Round(randoms[i] * d, 0) }); } sharedRedPacket.RobbedRedPackets.Add( new RobbedRedPacket { Amount = originalTotal - sharedRedPacket.RobbedRedPackets.Sum(p => p.Amount) }); |
測試
測試效果圖如下:
部分代碼如下,
1
2
3
4
5
6
7
8
9
|
Console.WriteLine( "是否分享輸入Y分享成功,輸入N退出" ); string result = Console.ReadLine(); if (result == "Y" ) { var leftRedPacket = sharedRedPacket.RobbedRedPackets.Where(p => p.UserId <= 0).ToList(); var robbedRedPacket = leftRedPacket[ new Random().Next(1, leftRedPacket.Count + 1)]; Console.WriteLine( "搶到的到紅包金額是:" + robbedRedPacket.Amount); Console.WriteLine( "-------------------------------------------------------" ); } |
總結
以上所述是小編給大家介紹的使用.NET Core實現餓了嗎拆紅包功能,希望對大家有所幫助,如果大家有任何疑問歡迎給我留言,小編會及時回復大家的!
原文鏈接:https://www.cnblogs.com/edison0621/p/11145095.html