UNPKG

5.29 kBJavaScriptView Raw
1import { flatten } from '../../utils/array.js';
2import { factory } from '../../utils/factory.js';
3import { isMatrix, isNumber } from '../../utils/is.js';
4import { createRng } from './util/seededRNG.js';
5var name = 'pickRandom';
6var dependencies = ['typed', 'config', '?on'];
7export 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({
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});
\No newline at end of file