js实现一个权重抽奖
权重抽奖实现方法
权重抽奖是一种根据每个奖项的权重值来随机抽取奖项的方法,权重越高,被抽中的概率越大。以下是使用JavaScript实现权重抽奖的几种方法。
方法一:基于数组的权重抽奖
定义一个奖项数组,每个奖项包含名称和权重。通过计算总权重,生成随机数,然后遍历数组确定中奖奖项。

function weightedDraw(prizes) {
let totalWeight = prizes.reduce((sum, prize) => sum + prize.weight, 0);
let random = Math.random() * totalWeight;
let currentWeight = 0;
for (let prize of prizes) {
currentWeight += prize.weight;
if (random <= currentWeight) {
return prize.name;
}
}
}
// 示例
const prizes = [
{ name: "一等奖", weight: 1 },
{ name: "二等奖", weight: 3 },
{ name: "三等奖", weight: 6 },
{ name: "谢谢参与", weight: 90 }
];
console.log(weightedDraw(prizes));
方法二:使用概率分布
将权重转换为概率分布,然后使用累积概率进行抽奖。这种方法适用于权重较大的情况。

function weightedDrawWithProbability(prizes) {
const totalWeight = prizes.reduce((sum, prize) => sum + prize.weight, 0);
const probabilities = prizes.map(prize => prize.weight / totalWeight);
const cumulativeProbabilities = [];
let sum = 0;
for (let prob of probabilities) {
sum += prob;
cumulativeProbabilities.push(sum);
}
const random = Math.random();
for (let i = 0; i < cumulativeProbabilities.length; i++) {
if (random <= cumulativeProbabilities[i]) {
return prizes[i].name;
}
}
}
// 示例
const prizes = [
{ name: "一等奖", weight: 1 },
{ name: "二等奖", weight: 3 },
{ name: "三等奖", weight: 6 },
{ name: "谢谢参与", weight: 90 }
];
console.log(weightedDrawWithProbability(prizes));
方法三:使用二分查找优化
当奖项数量较多时,可以使用二分查找来提高效率。首先计算累积权重数组,然后使用二分查找确定中奖奖项。
function weightedDrawWithBinarySearch(prizes) {
const totalWeight = prizes.reduce((sum, prize) => sum + prize.weight, 0);
const cumulativeWeights = [];
let sum = 0;
for (let prize of prizes) {
sum += prize.weight;
cumulativeWeights.push(sum);
}
const random = Math.random() * totalWeight;
let left = 0;
let right = cumulativeWeights.length - 1;
while (left < right) {
const mid = Math.floor((left + right) / 2);
if (random <= cumulativeWeights[mid]) {
right = mid;
} else {
left = mid + 1;
}
}
return prizes[left].name;
}
// 示例
const prizes = [
{ name: "一等奖", weight: 1 },
{ name: "二等奖", weight: 3 },
{ name: "三等奖", weight: 6 },
{ name: "谢谢参与", weight: 90 }
];
console.log(weightedDrawWithBinarySearch(prizes));
方法四:使用ES6的Map和reduce
利用ES6的Map和reduce方法简化代码,适用于现代JavaScript环境。
function weightedDrawWithMap(prizes) {
const totalWeight = prizes.reduce((sum, prize) => sum + prize.weight, 0);
const random = Math.random() * totalWeight;
let currentWeight = 0;
return prizes.find(prize => {
currentWeight += prize.weight;
return random <= currentWeight;
}).name;
}
// 示例
const prizes = [
{ name: "一等奖", weight: 1 },
{ name: "二等奖", weight: 3 },
{ name: "三等奖", weight: 6 },
{ name: "谢谢参与", weight: 90 }
];
console.log(weightedDrawWithMap(prizes));
注意事项
- 权重值可以是任意正数,但通常建议使用整数以便于计算和理解。
- 确保权重总和不为零,否则会导致抽奖失败。
- 对于大量奖项,建议使用方法三的二分查找以提高性能。
- 可以根据实际需求调整奖项和权重值,以适应不同的抽奖场景。






