需求
有一个红包算法,需求是总共发50000个,金额在75000元,每一个红包要求在1元到2元之间。
实现
暂时的实现没有考虑异常检查和优化,先贴代码后面再说吧。
public static List<decimal> RandomRedPacket(int packetCount, Decimal totalBonus, Decimal minBonus, Decimal maxBonus)
{
Random RandomEvent = new Random();
List<Decimal> resultList = new List<decimal>();
for (int i = 0; i < packetCount; i++)
{
if (i == packetCount-1)
{
resultList.Add(totalBonus);
}
else
{
decimal thisBonus=0.00m;
//平均值 剩余钱除以剩余红包数的平均值
decimal avgBonus = totalBonus / (packetCount - i);
if (avgBonus > maxBonus)
{
//随机区间为最小值到最大值之间 例如:1-2
thisBonus=RandomEvent.NextDecimal(minBonus, maxBonus );
}
else if (avgBonus < maxBonus && avgBonus>(maxBonus+minBonus)/2)
{
//随机区间为中间值到最大值之间 例如:>1.5-2
thisBonus = RandomEvent.NextDecimal(avgBonus, maxBonus);
}
else
{
//随机区间为最小值到中间值之间 例如:1-<1.5
thisBonus = RandomEvent.NextDecimal(minBonus, avgBonus);
}
thisBonus = Math.Round(thisBonus, 2);
resultList.Add(thisBonus);
totalBonus -= thisBonus;
}
}
return resultList;
}
其中给Random类扩展了一个获取Decimal的方法:
public static decimal NextDecimal(this Random rnd, decimal from, decimal to)
{
byte fromScale = new System.Data.SqlTypes.SqlDecimal(from).Scale;
byte toScale = new System.Data.SqlTypes.SqlDecimal(to).Scale;
byte scale = (byte)(fromScale + toScale);
if (scale > 28)
scale = 28;
decimal r = new decimal(rnd.Next(), rnd.Next(), rnd.Next(), false, scale);
if (Math.Sign(from) == Math.Sign(to) || from == 0 || to == 0)
return decimal.Remainder(r, to - from) + from;
bool getFromNegativeRange = (double)from + rnd.NextDouble() * ((double)to - (double)from) < 0;
return getFromNegativeRange ? decimal.Remainder(r, -from) + from : decimal.Remainder(r, to);
}
最终测试如下:
static void Main(string[] args)
{
for (int i = 0; i < 3; i++)
{
List<decimal> poker = RandomRedPacket(50, 75, 1.00m, 2.00m);
Decimal total = poker.Sum();
Console.WriteLine("红包生成队列的总和为:" + total);
Console.WriteLine("每一个红包都满足1-2之间的要求么:" + poker.TrueForAll(x => x >= 1 && x <= 2));
Console.WriteLine("红包生成队列:" + string.Join(",", poker.ToArray()));
}
Console.ReadLine();
}