多件商品根據概率抽獎
阿新 • • 發佈:2018-11-29
size 最大 clas implement 模塊 wid ood pri type
最近在項目中分配了一個抽獎模塊的任務,這裏先說一下需求把:每個抽獎活動後臺會配置多個中獎獎品,分為特殊獎品和普通獎品,所有獎品的中獎概率之和加起來為1。用戶端用戶抽獎需要根據概率來隨機抽中一個商品。開始我腦子生出來的第一想法是生成一個隨機數,然後讓這個隨機數跟概率去比較,取小於這個隨機數的最大一個概率對應的商品為中獎商品,後來一想,發現自己想的太簡單直觀了,這樣抽中的商品中獎概率不滿足配置的中獎概率。在網上搜了一下相關的問題,然後就弄清楚了。說來慚愧,這麽一個簡單的算法題,自己竟然第一時間沒有沒有想到。所以在這裏把這個問題記錄下來。
public class DrawGoodsDO implementsComparable<DrawGoodsDO>{ //主鍵id private long id; //抽獎id private long drawId; //商品名稱 private String goodsName; //商品圖片地址 private String goodsImageUrl; //上架庫存 private int drawStock; //當前庫存 private int drawStockCur; //商品類型,1特殊商品,2普通商品 private int goodsType;// 中獎概率 private double drawRate; // 添加時間 private Timestamp addTime; //商品圖片地址,絕對路徑 private String goodsImageUrlFormat; /** * 商品圖片地址,絕對路徑 * * @return GoodsImageUrlFormat the GoodsImageUrlFormat */ public String getGoodsImageUrlFormat() { return goodsImageUrlFormat; }/** * 商品圖片地址,絕對路徑 * * @param goodsImageUrlFormat the goodsImageUrlFormat to set */ public void setGoodsImageUrlFormat(String goodsImageUrlFormat) { this.goodsImageUrlFormat = goodsImageUrlFormat; } //主鍵id public long getId() { return this.id; } //主鍵id public void setId(long id) { this.id = id; } //抽獎id public long getDrawId() { return this.drawId; } //抽獎id public void setDrawId(long drawId) { this.drawId = drawId; } //商品名稱 public String getGoodsName() { return this.goodsName; } //商品名稱 public void setGoodsName(String goodsName) { this.goodsName = goodsName; } //商品圖片地址 public String getGoodsImageUrl() { return this.goodsImageUrl; } //商品圖片地址 public void setGoodsImageUrl(String goodsImageUrl) { if (goodsImageUrl != null) { setGoodsImageUrlFormat(FileUrlConfig.file_visit_url + goodsImageUrl); } this.goodsImageUrl = goodsImageUrl; } //上架庫存 public int getDrawStock() { return this.drawStock; } //上架庫存 public void setDrawStock(int drawStock) { this.drawStock = drawStock; } //當前庫存 public int getDrawStockCur() { return this.drawStockCur; } //當前庫存 public void setDrawStockCur(int drawStockCur) { this.drawStockCur = drawStockCur; } //商品類型,1特殊商品,2普通商品 public int getGoodsType() { return this.goodsType; } //商品類型,1特殊商品,2普通商品 public void setGoodsType(int goodsType) { this.goodsType = goodsType; } // 獲取 中獎概率 public double getDrawRate() { return this.drawRate; } // 設置 中獎概率 public void setDrawRate(double drawRate) { this.drawRate = drawRate; } // 獲取 添加時間 public Timestamp getAddTime() { return this.addTime; } // 設置 添加時間 public void setAddTime(Timestamp addTime) { this.addTime = addTime; } @Override public int compareTo(DrawGoodsDO drawGoods) { if (this.drawRate >= drawGoods.getDrawRate()) { return 1; } return -1; } }
這個是抽獎獎品實體類,他實現了Comparable接口,實現了compareTo()方法,這個方法很重要,後面再說。
/** * 從抽獎獎品列表中隨機抽中一個 * * @param drawGoodsList 獎品列表 * @return */ private DrawGoodsDO randomGetDrawGoods(List<DrawGoodsDO> drawGoodsList) { if (ValidateUtil.isNull(drawGoodsList)) { return null; } //將獎品按概率從小到大排序 Collections.sort(drawGoodsList); //求出總概率 double sumRate = 0D; for (DrawGoodsDO drawGoodsDO : drawGoodsList) { sumRate += drawGoodsDO.getDrawRate(); } if (sumRate != 100) { //如果總概率之和不為100,重新計算他們的概率,讓他們的概率和為100 for (DrawGoodsDO drawGoodsDO : drawGoodsList) { drawGoodsDO.setDrawRate(drawGoodsDO.getDrawRate() * 100 / sumRate); } } //將每個獎品中獎區間段保存到list裏面 List<Double> list = new ArrayList<>(); double rate = 0D; for (DrawGoodsDO drawGoodsDO : drawGoodsList) { rate += drawGoodsDO.getDrawRate() / sumRate; list.add(rate); } //找出符合概率得獎品所占的索引位置 int index = 0; double randomNum = Math.random(); for (int i=0;i<list.size();i++) { if (randomNum > list.get(i)) { index = i + 1; } } return drawGoodsList.get(index); }
上面就是主要的實現方法,這裏最重要的就是先將獎品列表按照概率從小到大排序,因為Collections.sort()方法需要列表元素實現Comparable接口。所以上面的實體類中才那樣寫。然後根據中獎概率算出中獎區間段並且保存到list中,最後在生成一個隨機數與這個中間區間段的list來比較,最後選中獎品。
多件商品根據概率抽獎