UNPKG

@dxzmpk/js-algorithms-data-structures

Version:

Algorithms and data-structures implemented on JavaScript

53 lines (48 loc) 1.75 kB
/** * 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, }; } } }