mirror of
https://github.com/trekhleb/javascript-algorithms.git
synced 2025-12-08 19:06:00 +00:00
* Add the link to the Weighted Random algorithm to the main README. * Add Weighted Random implementation and tests. * Add Weighted Random README. * Add Weighted Random README. * Add Weighted Random README.
53 lines
1.7 KiB
JavaScript
53 lines
1.7 KiB
JavaScript
/**
|
|
* Picks the random item based on its weight.
|
|
* The items with higher weight will be picked more often (with a higher probability).
|
|
*
|
|
* For example:
|
|
* - items = ['banana', 'orange', 'apple']
|
|
* - weights = [0, 0.2, 0.8]
|
|
* - weightedRandom(items, weights) in 80% of cases will return 'apple', in 20% of cases will return
|
|
* 'orange' and it will never return 'banana' (because probability of picking the banana is 0%)
|
|
*
|
|
* @param {any[]} items
|
|
* @param {number[]} weights
|
|
* @returns {{item: any, index: number}}
|
|
*/
|
|
/* eslint-disable consistent-return */
|
|
export default function weightedRandom(items, weights) {
|
|
if (items.length !== weights.length) {
|
|
throw new Error('Items and weights must be of the same size');
|
|
}
|
|
|
|
if (!items.length) {
|
|
throw new Error('Items must not be empty');
|
|
}
|
|
|
|
// Preparing the cumulative weights array.
|
|
// For example:
|
|
// - weights = [1, 4, 3]
|
|
// - cumulativeWeights = [1, 5, 8]
|
|
const cumulativeWeights = [];
|
|
for (let i = 0; i < weights.length; i += 1) {
|
|
cumulativeWeights[i] = weights[i] + (cumulativeWeights[i - 1] || 0);
|
|
}
|
|
|
|
// Getting the random number in a range of [0...sum(weights)]
|
|
// For example:
|
|
// - weights = [1, 4, 3]
|
|
// - maxCumulativeWeight = 8
|
|
// - range for the random number is [0...8]
|
|
const maxCumulativeWeight = cumulativeWeights[cumulativeWeights.length - 1];
|
|
const randomNumber = maxCumulativeWeight * Math.random();
|
|
|
|
// Picking the random item based on its weight.
|
|
// The items with higher weight will be picked more often.
|
|
for (let itemIndex = 0; itemIndex < items.length; itemIndex += 1) {
|
|
if (cumulativeWeights[itemIndex] >= randomNumber) {
|
|
return {
|
|
item: items[itemIndex],
|
|
index: itemIndex,
|
|
};
|
|
}
|
|
}
|
|
}
|