UNPKG

8.41 kBJavaScriptView Raw
1import { isBigNumber } from '../../utils/is.js';
2import { format, sign } from '../../utils/number.js';
3import { factory } from '../../utils/factory.js';
4var name = 'Range';
5var dependencies = [];
6export var createRangeClass = /* #__PURE__ */factory(name, dependencies, () => {
7 /**
8 * Create a range. A range has a start, step, and end, and contains functions
9 * to iterate over the range.
10 *
11 * A range can be constructed as:
12 *
13 * const range = new Range(start, end)
14 * const range = new Range(start, end, step)
15 *
16 * To get the result of the range:
17 * range.forEach(function (x) {
18 * console.log(x)
19 * })
20 * range.map(function (x) {
21 * return math.sin(x)
22 * })
23 * range.toArray()
24 *
25 * Example usage:
26 *
27 * const c = new Range(2, 6) // 2:1:5
28 * c.toArray() // [2, 3, 4, 5]
29 * const d = new Range(2, -3, -1) // 2:-1:-2
30 * d.toArray() // [2, 1, 0, -1, -2]
31 *
32 * @class Range
33 * @constructor Range
34 * @param {number} start included lower bound
35 * @param {number} end excluded upper bound
36 * @param {number} [step] step size, default value is 1
37 */
38 function Range(start, end, step) {
39 if (!(this instanceof Range)) {
40 throw new SyntaxError('Constructor must be called with the new operator');
41 }
42
43 var hasStart = start !== null && start !== undefined;
44 var hasEnd = end !== null && end !== undefined;
45 var hasStep = step !== null && step !== undefined;
46
47 if (hasStart) {
48 if (isBigNumber(start)) {
49 start = start.toNumber();
50 } else if (typeof start !== 'number') {
51 throw new TypeError('Parameter start must be a number');
52 }
53 }
54
55 if (hasEnd) {
56 if (isBigNumber(end)) {
57 end = end.toNumber();
58 } else if (typeof end !== 'number') {
59 throw new TypeError('Parameter end must be a number');
60 }
61 }
62
63 if (hasStep) {
64 if (isBigNumber(step)) {
65 step = step.toNumber();
66 } else if (typeof step !== 'number') {
67 throw new TypeError('Parameter step must be a number');
68 }
69 }
70
71 this.start = hasStart ? parseFloat(start) : 0;
72 this.end = hasEnd ? parseFloat(end) : 0;
73 this.step = hasStep ? parseFloat(step) : 1;
74 }
75 /**
76 * Attach type information
77 */
78
79
80 Range.prototype.type = 'Range';
81 Range.prototype.isRange = true;
82 /**
83 * Parse a string into a range,
84 * The string contains the start, optional step, and end, separated by a colon.
85 * If the string does not contain a valid range, null is returned.
86 * For example str='0:2:11'.
87 * @memberof Range
88 * @param {string} str
89 * @return {Range | null} range
90 */
91
92 Range.parse = function (str) {
93 if (typeof str !== 'string') {
94 return null;
95 }
96
97 var args = str.split(':');
98 var nums = args.map(function (arg) {
99 return parseFloat(arg);
100 });
101 var invalid = nums.some(function (num) {
102 return isNaN(num);
103 });
104
105 if (invalid) {
106 return null;
107 }
108
109 switch (nums.length) {
110 case 2:
111 return new Range(nums[0], nums[1]);
112
113 case 3:
114 return new Range(nums[0], nums[2], nums[1]);
115
116 default:
117 return null;
118 }
119 };
120 /**
121 * Create a clone of the range
122 * @return {Range} clone
123 */
124
125
126 Range.prototype.clone = function () {
127 return new Range(this.start, this.end, this.step);
128 };
129 /**
130 * Retrieve the size of the range.
131 * Returns an array containing one number, the number of elements in the range.
132 * @memberof Range
133 * @returns {number[]} size
134 */
135
136
137 Range.prototype.size = function () {
138 var len = 0;
139 var start = this.start;
140 var step = this.step;
141 var end = this.end;
142 var diff = end - start;
143
144 if (sign(step) === sign(diff)) {
145 len = Math.ceil(diff / step);
146 } else if (diff === 0) {
147 len = 0;
148 }
149
150 if (isNaN(len)) {
151 len = 0;
152 }
153
154 return [len];
155 };
156 /**
157 * Calculate the minimum value in the range
158 * @memberof Range
159 * @return {number | undefined} min
160 */
161
162
163 Range.prototype.min = function () {
164 var size = this.size()[0];
165
166 if (size > 0) {
167 if (this.step > 0) {
168 // positive step
169 return this.start;
170 } else {
171 // negative step
172 return this.start + (size - 1) * this.step;
173 }
174 } else {
175 return undefined;
176 }
177 };
178 /**
179 * Calculate the maximum value in the range
180 * @memberof Range
181 * @return {number | undefined} max
182 */
183
184
185 Range.prototype.max = function () {
186 var size = this.size()[0];
187
188 if (size > 0) {
189 if (this.step > 0) {
190 // positive step
191 return this.start + (size - 1) * this.step;
192 } else {
193 // negative step
194 return this.start;
195 }
196 } else {
197 return undefined;
198 }
199 };
200 /**
201 * Execute a callback function for each value in the range.
202 * @memberof Range
203 * @param {function} callback The callback method is invoked with three
204 * parameters: the value of the element, the index
205 * of the element, and the Range being traversed.
206 */
207
208
209 Range.prototype.forEach = function (callback) {
210 var x = this.start;
211 var step = this.step;
212 var end = this.end;
213 var i = 0;
214
215 if (step > 0) {
216 while (x < end) {
217 callback(x, [i], this);
218 x += step;
219 i++;
220 }
221 } else if (step < 0) {
222 while (x > end) {
223 callback(x, [i], this);
224 x += step;
225 i++;
226 }
227 }
228 };
229 /**
230 * Execute a callback function for each value in the Range, and return the
231 * results as an array
232 * @memberof Range
233 * @param {function} callback The callback method is invoked with three
234 * parameters: the value of the element, the index
235 * of the element, and the Matrix being traversed.
236 * @returns {Array} array
237 */
238
239
240 Range.prototype.map = function (callback) {
241 var array = [];
242 this.forEach(function (value, index, obj) {
243 array[index[0]] = callback(value, index, obj);
244 });
245 return array;
246 };
247 /**
248 * Create an Array with a copy of the Ranges data
249 * @memberof Range
250 * @returns {Array} array
251 */
252
253
254 Range.prototype.toArray = function () {
255 var array = [];
256 this.forEach(function (value, index) {
257 array[index[0]] = value;
258 });
259 return array;
260 };
261 /**
262 * Get the primitive value of the Range, a one dimensional array
263 * @memberof Range
264 * @returns {Array} array
265 */
266
267
268 Range.prototype.valueOf = function () {
269 // TODO: implement a caching mechanism for range.valueOf()
270 return this.toArray();
271 };
272 /**
273 * Get a string representation of the range, with optional formatting options.
274 * Output is formatted as 'start:step:end', for example '2:6' or '0:0.2:11'
275 * @memberof Range
276 * @param {Object | number | function} [options] Formatting options. See
277 * lib/utils/number:format for a
278 * description of the available
279 * options.
280 * @returns {string} str
281 */
282
283
284 Range.prototype.format = function (options) {
285 var str = format(this.start, options);
286
287 if (this.step !== 1) {
288 str += ':' + format(this.step, options);
289 }
290
291 str += ':' + format(this.end, options);
292 return str;
293 };
294 /**
295 * Get a string representation of the range.
296 * @memberof Range
297 * @returns {string}
298 */
299
300
301 Range.prototype.toString = function () {
302 return this.format();
303 };
304 /**
305 * Get a JSON representation of the range
306 * @memberof Range
307 * @returns {Object} Returns a JSON object structured as:
308 * `{"mathjs": "Range", "start": 2, "end": 4, "step": 1}`
309 */
310
311
312 Range.prototype.toJSON = function () {
313 return {
314 mathjs: 'Range',
315 start: this.start,
316 end: this.end,
317 step: this.step
318 };
319 };
320 /**
321 * Instantiate a Range from a JSON object
322 * @memberof Range
323 * @param {Object} json A JSON object structured as:
324 * `{"mathjs": "Range", "start": 2, "end": 4, "step": 1}`
325 * @return {Range}
326 */
327
328
329 Range.fromJSON = function (json) {
330 return new Range(json.start, json.end, json.step);
331 };
332
333 return Range;
334}, {
335 isClass: true
336});
\No newline at end of file