pickRandom.js (5294B)
1 import { flatten } from '../../utils/array.js'; 2 import { factory } from '../../utils/factory.js'; 3 import { isMatrix, isNumber } from '../../utils/is.js'; 4 import { createRng } from './util/seededRNG.js'; 5 var name = 'pickRandom'; 6 var dependencies = ['typed', 'config', '?on']; 7 export var createPickRandom = /* #__PURE__ */factory(name, dependencies, _ref => { 8 var { 9 typed, 10 config, 11 on 12 } = _ref; 13 // seeded pseudo random number generator 14 var rng = createRng(config.randomSeed); 15 16 if (on) { 17 on('config', function (curr, prev) { 18 if (curr.randomSeed !== prev.randomSeed) { 19 rng = createRng(curr.randomSeed); 20 } 21 }); 22 } 23 /** 24 * Random pick one or more values from a one dimensional array. 25 * Array elements are picked using a random function with uniform or weighted distribution. 26 * 27 * Syntax: 28 * 29 * math.pickRandom(array) 30 * math.pickRandom(array, number) 31 * math.pickRandom(array, weights) 32 * math.pickRandom(array, number, weights) 33 * math.pickRandom(array, weights, number) 34 * math.pickRandom(array, { weights, number, elementWise }) 35 * 36 * Examples: 37 * 38 * math.pickRandom([3, 6, 12, 2]) // returns one of the values in the array 39 * math.pickRandom([3, 6, 12, 2], 2) // returns an array of two of the values in the array 40 * math.pickRandom([3, 6, 12, 2], { number: 2 }) // returns an array of two of the values in the array 41 * math.pickRandom([3, 6, 12, 2], [1, 3, 2, 1]) // returns one of the values in the array with weighted distribution 42 * math.pickRandom([3, 6, 12, 2], 2, [1, 3, 2, 1]) // returns an array of two of the values in the array with weighted distribution 43 * math.pickRandom([3, 6, 12, 2], [1, 3, 2, 1], 2) // returns an array of two of the values in the array with weighted distribution 44 * 45 * math.pickRandom([{x: 1.0, y: 2.0}, {x: 1.1, y: 2.0}], { elementWise: false }) 46 * // returns one of the items in the array 47 * 48 * See also: 49 * 50 * random, randomInt 51 * 52 * @param {Array | Matrix} array A one dimensional array 53 * @param {Int} number An int or float 54 * @param {Array | Matrix} weights An array of ints or floats 55 * @return {number | Array} Returns a single random value from array when number is 1 or undefined. 56 * Returns an array with the configured number of elements when number is > 1. 57 */ 58 59 60 return typed(name, { 61 'Array | Matrix': function ArrayMatrix(possibles) { 62 return _pickRandom(possibles, {}); 63 }, 64 'Array | Matrix, Object': function ArrayMatrixObject(possibles, options) { 65 return _pickRandom(possibles, options); 66 }, 67 'Array | Matrix, number': function ArrayMatrixNumber(possibles, number) { 68 return _pickRandom(possibles, { 69 number 70 }); 71 }, 72 'Array | Matrix, Array | Matrix': function ArrayMatrixArrayMatrix(possibles, weights) { 73 return _pickRandom(possibles, { 74 weights 75 }); 76 }, 77 'Array | Matrix, Array | Matrix, number': function ArrayMatrixArrayMatrixNumber(possibles, weights, number) { 78 return _pickRandom(possibles, { 79 number, 80 weights 81 }); 82 }, 83 'Array | Matrix, number, Array | Matrix': function ArrayMatrixNumberArrayMatrix(possibles, number, weights) { 84 return _pickRandom(possibles, { 85 number, 86 weights 87 }); 88 } 89 }); 90 /** 91 * @param {Array | Matrix} possibles 92 * @param {{ 93 * number?: number, 94 * weights?: Array | Matrix, 95 * elementWise: boolean 96 * }} options 97 * @returns {number | Array} 98 * @private 99 */ 100 101 function _pickRandom(possibles, _ref2) { 102 var { 103 number, 104 weights, 105 elementWise = true 106 } = _ref2; 107 var single = typeof number === 'undefined'; 108 109 if (single) { 110 number = 1; 111 } 112 113 var createMatrix = isMatrix(possibles) ? possibles.create : isMatrix(weights) ? weights.create : null; 114 possibles = possibles.valueOf(); // get Array 115 116 if (weights) { 117 weights = weights.valueOf(); // get Array 118 } 119 120 if (elementWise === true) { 121 possibles = flatten(possibles); 122 weights = flatten(weights); 123 } 124 125 var totalWeights = 0; 126 127 if (typeof weights !== 'undefined') { 128 if (weights.length !== possibles.length) { 129 throw new Error('Weights must have the same length as possibles'); 130 } 131 132 for (var i = 0, len = weights.length; i < len; i++) { 133 if (!isNumber(weights[i]) || weights[i] < 0) { 134 throw new Error('Weights must be an array of positive numbers'); 135 } 136 137 totalWeights += weights[i]; 138 } 139 } 140 141 var length = possibles.length; 142 var result = []; 143 var pick; 144 145 while (result.length < number) { 146 if (typeof weights === 'undefined') { 147 pick = possibles[Math.floor(rng() * length)]; 148 } else { 149 var randKey = rng() * totalWeights; 150 151 for (var _i = 0, _len = possibles.length; _i < _len; _i++) { 152 randKey -= weights[_i]; 153 154 if (randKey < 0) { 155 pick = possibles[_i]; 156 break; 157 } 158 } 159 } 160 161 result.push(pick); 162 } 163 164 return single ? result[0] : createMatrix ? createMatrix(result) : result; 165 } 166 });