随机数与百分比

问题描述 投票:0回答:4

我有这个:

var users = [user1, user2, user3];
var chances = [20, 20, 60];
var total = 100;
var random = Math.floor((Math.random() * total) + 1);

if (random > 40 && random < 100) {
    console.log('winner:', users[2]);
}

if (random > 20 && random < 40) {
    console.log('winner:', users[1]);
}

if (random > 0 && random < 20) {
    console.log('winner:', users[0]);
}

这将为每个用户提供公平的获胜机会。 (60有60%的几率,20有20%的几率)。

但我真正需要的是,这是每个(或任何其他)功能的动态。

我的想法的例子:

 chances.forEach(function(entry) {
     if (unknownValue > unkownValue2 && unknownValue3 < unknownValue4) {
         console.log('winner:', unknownUser);
     };
 });

所以基本上,如果机会数组的值是50,100和20,则数字100获胜的机会必须比50高出2倍,比20高出5倍。

我很高兴每一个答案,请不要将此标记为老虎机百分比的重复,这不是我需要的。

javascript arrays sorting random percentage
4个回答
2
投票

作为概率解决方案的替代方案,您还可以创建具有重复用户的阵列,以使其计数对应于关联的百分比。然后要求您的百分比是正整数,而不是分数。

像这样:

const users = [
  {name: "Jim",   pct: 20},
  {name: "Helen", pct: 20},
  {name: "Anna",  pct: 60}
];

const expanded = users.flatMap(user => Array(user.pct).fill(user));
const winner = expanded[Math.floor(Math.random() * expanded.length)];
console.log("winner: " + winner.name);

这些数字实际上不一定是百分比。如果您需要更高的精度,只需使用可能加起来1000或10000的更大数字。


1
投票

将比率转换为百分比。显然,他们的总和应该占1,并且每个的值是val/total

function transformRatiosToAccPercentages(ratios) {
  const total = ratios.reduce((sum, el) => sum += el, 0);
  let acc = 0;
  const accPercentages = ratios.map(rat => acc += rat / total);
  return accPercentages;
}

function chooseBiasedRandom(accPercentages) {
  const random = Math.random();
  const index = accPercentages.findIndex(acc => random < acc);
  return index;
}

// And that's how it can be used:

const users = {
  Alpha: 50,
  Bravo: 100,
  Charlie: 10
};

const userNames = Object.keys(users); 
const ratios = Object.values(users);

const attempts = 1E6;
const counter = Array(userNames.length).fill(0);

const accPercentages = transformRatiosToAccPercentages(ratios);

for (let i = 1; i <= attempts; i++) {
  const index = chooseBiasedRandom(accPercentages);
  counter[index]++;
  // console.log(`Attempt ${i}: user ${userNames[index]} wins!`);
}

console.log(counter);

1
投票

    //put chances and user object in the same object, in an array
    let userChances = [
        {userObj: 'user1', chance: 20},
        {userObj: 'user2', chance: 40},
        {userObj: 'user2', chance: 60}
    ];
    //we loop the items and turn the chance into a running total...
    for (let i = 0; i < userChances.length; i++) {
        if (i > 0) {
            userChances[i] = {
                userObj: userChances[i].userObj,
                chance: userChances[i].chance + userChances[i - 1].chance
            };
        }
    }
    //now data looks like this:
    //let userChances = [
    //    {userObj: user1, chance: 20},
    //    {userObj: user2, chance: 60},
    //    {userObj: user2, chance: 120}
    //];
    //we get the total available chance, which is now the value of the chance property of the last element in the array
    let totalChances = userChances[userChances.length - 1].chance;
    let yourChance = Math.floor((Math.random() * totalChances) + 1);
    //loop one last time
    for (let i= 0; i < userChances.length; i ++) {
        //if our number is less than the current user chance, we found the user! return it! otherwise, proceed to check the next user...
        if (yourChance <= userChances[i].chance) {
            console.log('Winner', userChances[i].userObj);
            break;
        }
        //please note that if this does not return or break the loop, every user after this will be logged as a winner too!
    }

1
投票

您可以使用具有概率的数组,并检查并计算随机值。

此函数首先将返回值设置为最后一个可能的索引,然后迭代直到随机值的其余部分小于实际概率。此外,所有概率的总和应等于1。

对于实现,您只需要获取用于获取用户数组索引的函数。

var users = ['user1', 'user2', 'user3'],
    probabilities = [0.2, 0.2, 0.6],
    selectedUser = users[getRandomIndexByProbability(probabilities)];

然后,代码显示索引的分布。

function getRandomIndexByProbability(probabilities) {
    var r = Math.random(),
        index = probabilities.length - 1;

    probabilities.some(function (probability, i) {
        if (r < probability) {
            index = i;
            return true;
        }
        r -= probability;
    });
    return index;
}

var i,
    probabilities = [0.2, 0.2, 0.6],
    count = {},
    index;

probabilities.forEach(function (_, i) { count[i] = 0; });

for (i = 0; i < 1e6; i++) {
    index = getRandomIndexByProbability(probabilities);
    count[index]++;
}

console.log(count);
.as-console-wrapper { max-height: 100% !important; top: 0; }
© www.soinside.com 2019 - 2024. All rights reserved.