公平概率抽奖算法工具类分享
- 支持按概率权重抽奖
- 支持奖品动态增减
- 支持泛型传参
- 返回奖品
依赖hutool
工具类,可进一步改造成带库存的奖品,我这里暂时用不到库存就不改造了,有大佬改造好了请留言~
工具类
代码语言:javascript复制 /**
* 抽奖,返回抽到的奖品
* @param prizeList 奖品列表
* @return T
* @exception
* @author GMQ
* @date 2022/2/18 21:18
**/
public static <T> T lottery(List<T> prizeList){
if (CollUtil.isEmpty(prizeList)){
return null;
}
//概率总和
BigDecimal rateSum = BigDecimal.ZERO;
for (T t1 : prizeList) {
Map map = Convert.convert(HashMap.class, t1);
rateSum = NumberUtil.add(rateSum,NumberUtil.toBigDecimal(map.get("winnRate") ""));
}
BigDecimal temp = BigDecimal.ZERO;
//比值
List<BigDecimal> tempList = new ArrayList<>(prizeList.size());
for (T t1 : prizeList) {
Map map = Convert.convert(HashMap.class, t1);
temp = temp.add(NumberUtil.toBigDecimal(map.get("winnRate") ""));
tempList.add(NumberUtil.div(temp,rateSum,8));
}
BigDecimal value = NumberUtil.round(RandomUtil.randomBigDecimal(),8);
tempList.add(value);
Collections.sort(tempList);
int index = tempList.indexOf(value);
T win = prizeList.get(index);
return win;
}
使用示例
代码语言:javascript复制 @Test
void f5(){
List<Map> list = new ArrayList<>();
Map map1 = new HashMap();
map1.put("name","现金红包200");
map1.put("winnRate","47");
list.add(map1);
Map map2 = new HashMap();
map2.put("name","小米运动手表");
map2.put("winnRate","30");
list.add(map2);
Map map3 = new HashMap();
map3.put("name","手机");
map3.put("winnRate","10");
list.add(map3);
Map map4 = new HashMap();
map4.put("name","苹果电脑");
map4.put("winnRate","5");
list.add(map4);
// Map map5 = new HashMap();
// map5.put("name","三亚五日游");
// map5.put("winnRate","1");
// list.add(map5);
BigDecimal rateSum = BigDecimal.ZERO;
for (Map map : list) {
rateSum = NumberUtil.add(rateSum,NumberUtil.toBigDecimal(map.get("winnRate") ""));
}
System.out.println("概率总和:" rateSum);
Map map = new HashMap();
// 抽取100次
for (int i = 0; i < 100; i ) {
Map win = LotteryUtil.lottery(list);
map.put(win.get("name"),map.get(win.get("name"))==null?1:Integer.valueOf(map.get(win.get("name")) "") 1);
}
System.out.println("抽中统计:" JSON.toJSONString(map));
}