Skip to content

Instantly share code, notes, and snippets.

@azerum
Created May 15, 2022 19:08
Show Gist options
  • Select an option

  • Save azerum/a20c1c2d58707cce54ac904ebecadb5c to your computer and use it in GitHub Desktop.

Select an option

Save azerum/a20c1c2d58707cce54ac904ebecadb5c to your computer and use it in GitHub Desktop.
/**
* 'probabilities' is an array of pairs [probability, choice]
*/
function chooseWithProbabilities(probabilities) {
const pSum = probabilities.reduce((sum, [p, _]) => sum + p, 0);
if (pSum !== 100.0) {
throw new Error(
'Sum of the probabilities must be equal to 100. '
+ `Current sum is ${pSum}`
);
}
probabilities.sort(([p1, _], [p2, __]) => p1 - p2);
//generatedP is in range [0, 100)
let generatedP = Math.random() * 100;
for (const [p, choice] of probabilities) {
if (generatedP <= p) {
return choice;
}
generatedP -= p;
}
}
//Code to test the function
const probabilities = [
[10, 'a'],
[20, 'b'],
[50, 'c'],
[20, 'd']
];
const choicesToCounts = {
'a': 0,
'b': 0,
'c': 0,
'd': 0
};
const totalExperiments = 100_000_000;
for (let i = 0; i < totalExperiments; ++i) {
const choice = chooseWithProbabilities(probabilities);
++choicesToCounts[choice];
}
for (const [choice, count] of Object.entries(choicesToCounts)) {
const p = count / totalExperiments * 100;
const [expectedP, _] = probabilities.find(([_, c]) => c === choice);
console.log(`${choice}: p = ${p}, expectedP = ${expectedP}`);
}
@azerum
Copy link
Author

azerum commented May 15, 2022

ES5 version:

/**
 * 'probabilities' is an array of pairs [probability, choice]
 */
function chooseWithProbabilities(probabilities) {
    var pSum = probabilities.reduce(function (sum, pair) {
        return sum + pair[0]; 
    }, 0);
    
    if (pSum !== 100.0) {
        throw new Error(
            'Sum of the probabilities must be equal to 100. '
            + 'Current sum is' + pSum
        );
    }

    probabilities.sort(function (pair1, pair2) {
        return pair1[0] - pair2[0];
    });

    //generatedP is in range [0, 100)
    var generatedP = Math.random() * 100;
    
    for (var i = 0; i < probabilities.length; ++i) {
        var pair = probabilities[i];
        
        var p = pair[0];
        var choice = pair[1];
        
        if (generatedP <= p) {
            return choice;
        }
        
        generatedP -= p;
    }
}

//Code to test the function

var probabilities = [
    [10, 'a'],
    [20, 'b'],
    [50, 'c'],
    [20, 'd']
];

var choicesToCounts = {
    'a': 0,
    'b': 0,
    'c': 0,
    'd': 0
};

var totalExperiments = 100000000;

for (var i = 0; i < totalExperiments; ++i) {
    var choice = chooseWithProbabilities(probabilities);
    ++choicesToCounts[choice];
}

var entries = Object.entries(choicesToCounts);

for (var i = 0; i < entries.length; ++i) {
    var e = entries[i];
    
    var p = e[0];
    var choice = e[1];

    var expectedP = probabilities.find(function (pair) {
        return pair[1] === choice;
    });

    console.log(choice + ': p = ' + p + ', expectedP = ' + expectedP);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment