js实现一个权重抽奖

权重抽奖实现方法
权重抽奖的核心是根据不同奖项的权重值计算概率,并通过随机数选择对应的奖项。以下是基于JavaScript的实现方法:
方法一:使用累积概率区间
function weightedDraw(prizes) {
// 计算总权重
const totalWeight = prizes.reduce((sum, prize) => sum + prize.weight, 0);
// 生成随机数
const random = Math.random() * totalWeight;
// 遍历奖品计算累积权重
let currentWeight = 0;
for (const prize of prizes) {
currentWeight += prize.weight;
if (random <= currentWeight) {
return prize;
}
}
// 默认返回最后一个
return prizes[prizes.length - 1];
}
// 使用示例
const prizes = [
{ name: "一等奖", weight: 1 },
{ name: "二等奖", weight: 3 },
{ name: "三等奖", weight: 6 }
];
const result = weightedDraw(prizes);
console.log(result.name);
方法二:预计算概率表(适合高频调用)
class WeightedRandom {
constructor(items) {
this.total = items.reduce((sum, item) => sum + item.weight, 0);
this.table = items.map(item => ({
value: item.value,
threshold: item.weight / this.total
}));
// 计算累积概率
let accum = 0;
this.table = this.table.map(item => {
accum += item.threshold;
return { ...item, accum };
});
}
draw() {
const random = Math.random();
return this.table.find(item => random <= item.accum)?.value;
}
}
// 使用示例
const wr = new WeightedRandom([
{ value: "黄金", weight: 10 },
{ value: "白银", weight: 30 },
{ value: "青铜", weight: 60 }
]);
console.log(wr.draw());
方法三:ES6优化版本
const weightedRandom = (items) => {
const total = items.reduce((acc, { weight }) => acc + weight, 0);
const rand = Math.random() * total;
let sum = 0;
return items.find(({ weight }) => (sum += weight) >= rand)?.item;
};
// 使用示例
const items = [
{ item: "iPhone", weight: 5 },
{ item: "iPad", weight: 15 },
{ item: "优惠券", weight: 80 }
];
console.log(weightedRandom(items));
关键点说明
- 权重值可以是任意正数,不需要总和为1或100
- 权重越大被抽中的概率越高
- 算法时间复杂度为O(n),对于大量选项可考虑二分查找优化
- 随机数生成使用
Math.random(),如需更安全随机数可使用crypto.getRandomValues()
实际应用扩展
对于需要展示概率分布的场景,可先计算各奖项的实际概率:
function calculateProbabilities(prizes) {
const total = prizes.reduce((sum, p) => sum + p.weight, 0);
return prizes.map(p => ({
...p,
probability: (p.weight / total * 100).toFixed(2) + '%'
}));
}
以上实现可根据具体需求调整,如添加重复抽奖限制、奖品库存控制等功能。







