部分原文自: https://blog.csdn.net/larva_s/article/details/87532195java
根據配置獎品的機率去抽取獎品,其中總機率不必定是 1 ,此時是按照權重去抽取獎品的。數組
區間 | [0, 10):獎品1 | [10, 65):謝謝參與 | [65, 98):獎品2 | [98, 100):獎品3 |
機率 | 獎品1機率:10 | 謝謝參與機率:55 | 獎品2機率:33 | 獎品3機率:2 |
/** * 獎品類 */ @Data @AllArgsConstructor public class Award { private Integer id; private String name; private Integer weight; } /** * 通用抽獎接口 * @param <T> */ public interface ILotteryService<T> { T draw(List<T> awardList) throws DrawException; } /** * 區間實現抽獎機率 */ public class IntervalLotteryService implements ILotteryService<Award>{ /** * 經過區間來實現機率分配 * 獎品1 [0,10) * 獎品2 [10,90) * 獎品3 [90,100) * 獎品4 [100,980) * @param awardList * @return */ @Override public Award draw(List<Award> awardList) throws DrawException { int listSize = awardList.size(); if (awardList == null || listSize < 1){ return null; } // 遍歷list,計算區間最右值,封裝到 int數組中 中 int[] interval = new int[listSize]; for (int i = 0; i < listSize; i++) { Award award = awardList.get(i); Integer weight = award.getWeight(); if (i == 0){ interval[0] = weight; }else { Integer lastAwardWeight = interval[i - 1]; // 區間最右是上一個 區間最右 + 本身的權重 interval[i] = weight + lastAwardWeight; } } // random int 獲取隨機到的值 int maxInterval = interval[listSize - 1]; Random random = new Random(); int ranVal = random.nextInt(maxInterval); // 遍歷 int數組 ,找到隨機值是位於哪一個區間,獲取award,返回該award for (int i = 0; i < interval.length; i++) { if (ranVal >= interval[i] && ranVal < interval[i + 1]){ return awardList.get(i + 1); }else if (ranVal < interval[0]){ // 第一個區間以內 return awardList.get(0); } } throw new DrawException("抽獎異常"); } // 測試 public static void main(String args[]){ IntervalLotteryService lotteryService = new IntervalLotteryService(); List<Award> awardList = Lists.newArrayList( new Award(1,"0.088 機率獎品", 88), new Award(2,"0.333 機率獎品", 333), new Award(3,"0.155 機率獎品", 155), new Award(4,"0.424 機率獎品", 424) ); try { Map<String, Integer> statMap = Maps.newHashMap(); for (int i = 0; i < 1000; i++) { Award drawAward = lotteryService.draw(awardList); String awardName = drawAward.getName(); if (statMap.containsKey(awardName)){ Integer count = statMap.get(awardName); statMap.put(awardName, count + 1); }else { statMap.put(awardName, 1); } } statMap.forEach((k, v) -> System.out.println(k + " : " + v)); /* 0.088 機率獎品 : 94 0.155 機率獎品 : 152 0.333 機率獎品 : 320 0.424 機率獎品 : 434 */ } catch (DrawException e) { System.out.println("拋異常"); } } }
發獎失敗,包括拋異常等狀況,都設爲抽不到獎品,兜底處理便可。dom
仍然可被抽中,只不過扣庫存時發現庫存已消耗完則返回謝謝參與ide