UNPKG

8.84 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.createCompareNatural = void 0;
7
8var _javascriptNaturalSort = _interopRequireDefault(require("javascript-natural-sort"));
9
10var _is = require("../../utils/is.js");
11
12var _factory = require("../../utils/factory.js");
13
14function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
15
16var name = 'compareNatural';
17var dependencies = ['typed', 'compare'];
18var createCompareNatural = /* #__PURE__ */(0, _factory.factory)(name, dependencies, function (_ref) {
19 var typed = _ref.typed,
20 compare = _ref.compare;
21 var compareBooleans = compare.signatures['boolean,boolean'];
22 /**
23 * Compare two values of any type in a deterministic, natural way.
24 *
25 * For numeric values, the function works the same as `math.compare`.
26 * For types of values that can't be compared mathematically,
27 * the function compares in a natural way.
28 *
29 * For numeric values, x and y are considered equal when the relative
30 * difference between x and y is smaller than the configured epsilon.
31 * The function cannot be used to compare values smaller than
32 * approximately 2.22e-16.
33 *
34 * For Complex numbers, first the real parts are compared. If equal,
35 * the imaginary parts are compared.
36 *
37 * Strings are compared with a natural sorting algorithm, which
38 * orders strings in a "logic" way following some heuristics.
39 * This differs from the function `compare`, which converts the string
40 * into a numeric value and compares that. The function `compareText`
41 * on the other hand compares text lexically.
42 *
43 * Arrays and Matrices are compared value by value until there is an
44 * unequal pair of values encountered. Objects are compared by sorted
45 * keys until the keys or their values are unequal.
46 *
47 * Syntax:
48 *
49 * math.compareNatural(x, y)
50 *
51 * Examples:
52 *
53 * math.compareNatural(6, 1) // returns 1
54 * math.compareNatural(2, 3) // returns -1
55 * math.compareNatural(7, 7) // returns 0
56 *
57 * math.compareNatural('10', '2') // returns 1
58 * math.compareText('10', '2') // returns -1
59 * math.compare('10', '2') // returns 1
60 *
61 * math.compareNatural('Answer: 10', 'Answer: 2') // returns 1
62 * math.compareText('Answer: 10', 'Answer: 2') // returns -1
63 * math.compare('Answer: 10', 'Answer: 2')
64 * // Error: Cannot convert "Answer: 10" to a number
65 *
66 * const a = math.unit('5 cm')
67 * const b = math.unit('40 mm')
68 * math.compareNatural(a, b) // returns 1
69 *
70 * const c = math.complex('2 + 3i')
71 * const d = math.complex('2 + 4i')
72 * math.compareNatural(c, d) // returns -1
73 *
74 * math.compareNatural([1, 2, 4], [1, 2, 3]) // returns 1
75 * math.compareNatural([1, 2, 3], [1, 2]) // returns 1
76 * math.compareNatural([1, 5], [1, 2, 3]) // returns 1
77 * math.compareNatural([1, 2], [1, 2]) // returns 0
78 *
79 * math.compareNatural({a: 2}, {a: 4}) // returns -1
80 *
81 * See also:
82 *
83 * compare, compareText
84 *
85 * @param {*} x First value to compare
86 * @param {*} y Second value to compare
87 * @return {number} Returns the result of the comparison:
88 * 1 when x > y, -1 when x < y, and 0 when x == y.
89 */
90
91 return typed(name, {
92 'any, any': function anyAny(x, y) {
93 var typeX = (0, _is.typeOf)(x);
94 var typeY = (0, _is.typeOf)(y);
95 var c; // numeric types
96
97 if ((typeX === 'number' || typeX === 'BigNumber' || typeX === 'Fraction') && (typeY === 'number' || typeY === 'BigNumber' || typeY === 'Fraction')) {
98 c = compare(x, y);
99
100 if (c.toString() !== '0') {
101 // c can be number, BigNumber, or Fraction
102 return c > 0 ? 1 : -1; // return a number
103 } else {
104 return (0, _javascriptNaturalSort["default"])(typeX, typeY);
105 }
106 } // matrix types
107
108
109 if (typeX === 'Array' || typeX === 'Matrix' || typeY === 'Array' || typeY === 'Matrix') {
110 c = compareMatricesAndArrays(this, x, y);
111
112 if (c !== 0) {
113 return c;
114 } else {
115 return (0, _javascriptNaturalSort["default"])(typeX, typeY);
116 }
117 } // in case of different types, order by name of type, i.e. 'BigNumber' < 'Complex'
118
119
120 if (typeX !== typeY) {
121 return (0, _javascriptNaturalSort["default"])(typeX, typeY);
122 }
123
124 if (typeX === 'Complex') {
125 return compareComplexNumbers(x, y);
126 }
127
128 if (typeX === 'Unit') {
129 if (x.equalBase(y)) {
130 return this(x.value, y.value);
131 } // compare by units
132
133
134 return compareArrays(this, x.formatUnits(), y.formatUnits());
135 }
136
137 if (typeX === 'boolean') {
138 return compareBooleans(x, y);
139 }
140
141 if (typeX === 'string') {
142 return (0, _javascriptNaturalSort["default"])(x, y);
143 }
144
145 if (typeX === 'Object') {
146 return compareObjects(this, x, y);
147 }
148
149 if (typeX === 'null') {
150 return 0;
151 }
152
153 if (typeX === 'undefined') {
154 return 0;
155 } // this should not occur...
156
157
158 throw new TypeError('Unsupported type of value "' + typeX + '"');
159 }
160 });
161 /**
162 * Compare mixed matrix/array types, by converting to same-shaped array.
163 * This comparator is non-deterministic regarding input types.
164 * @param {Array | SparseMatrix | DenseMatrix | *} x
165 * @param {Array | SparseMatrix | DenseMatrix | *} y
166 * @returns {number} Returns the comparison result: -1, 0, or 1
167 */
168
169 function compareMatricesAndArrays(compareNatural, x, y) {
170 if ((0, _is.isSparseMatrix)(x) && (0, _is.isSparseMatrix)(y)) {
171 return compareArrays(compareNatural, x.toJSON().values, y.toJSON().values);
172 }
173
174 if ((0, _is.isSparseMatrix)(x)) {
175 // note: convert to array is expensive
176 return compareMatricesAndArrays(compareNatural, x.toArray(), y);
177 }
178
179 if ((0, _is.isSparseMatrix)(y)) {
180 // note: convert to array is expensive
181 return compareMatricesAndArrays(compareNatural, x, y.toArray());
182 } // convert DenseArray into Array
183
184
185 if ((0, _is.isDenseMatrix)(x)) {
186 return compareMatricesAndArrays(compareNatural, x.toJSON().data, y);
187 }
188
189 if ((0, _is.isDenseMatrix)(y)) {
190 return compareMatricesAndArrays(compareNatural, x, y.toJSON().data);
191 } // convert scalars to array
192
193
194 if (!Array.isArray(x)) {
195 return compareMatricesAndArrays(compareNatural, [x], y);
196 }
197
198 if (!Array.isArray(y)) {
199 return compareMatricesAndArrays(compareNatural, x, [y]);
200 }
201
202 return compareArrays(compareNatural, x, y);
203 }
204 /**
205 * Compare two Arrays
206 *
207 * - First, compares value by value
208 * - Next, if all corresponding values are equal,
209 * look at the length: longest array will be considered largest
210 *
211 * @param {Array} x
212 * @param {Array} y
213 * @returns {number} Returns the comparison result: -1, 0, or 1
214 */
215
216
217 function compareArrays(compareNatural, x, y) {
218 // compare each value
219 for (var i = 0, ii = Math.min(x.length, y.length); i < ii; i++) {
220 var v = compareNatural(x[i], y[i]);
221
222 if (v !== 0) {
223 return v;
224 }
225 } // compare the size of the arrays
226
227
228 if (x.length > y.length) {
229 return 1;
230 }
231
232 if (x.length < y.length) {
233 return -1;
234 } // both Arrays have equal size and content
235
236
237 return 0;
238 }
239 /**
240 * Compare two objects
241 *
242 * - First, compare sorted property names
243 * - Next, compare the property values
244 *
245 * @param {Object} x
246 * @param {Object} y
247 * @returns {number} Returns the comparison result: -1, 0, or 1
248 */
249
250
251 function compareObjects(compareNatural, x, y) {
252 var keysX = Object.keys(x);
253 var keysY = Object.keys(y); // compare keys
254
255 keysX.sort(_javascriptNaturalSort["default"]);
256 keysY.sort(_javascriptNaturalSort["default"]);
257 var c = compareArrays(compareNatural, keysX, keysY);
258
259 if (c !== 0) {
260 return c;
261 } // compare values
262
263
264 for (var i = 0; i < keysX.length; i++) {
265 var v = compareNatural(x[keysX[i]], y[keysY[i]]);
266
267 if (v !== 0) {
268 return v;
269 }
270 }
271
272 return 0;
273 }
274});
275/**
276 * Compare two complex numbers, `x` and `y`:
277 *
278 * - First, compare the real values of `x` and `y`
279 * - If equal, compare the imaginary values of `x` and `y`
280 *
281 * @params {Complex} x
282 * @params {Complex} y
283 * @returns {number} Returns the comparison result: -1, 0, or 1
284 */
285
286exports.createCompareNatural = createCompareNatural;
287
288function compareComplexNumbers(x, y) {
289 if (x.re > y.re) {
290 return 1;
291 }
292
293 if (x.re < y.re) {
294 return -1;
295 }
296
297 if (x.im > y.im) {
298 return 1;
299 }
300
301 if (x.im < y.im) {
302 return -1;
303 }
304
305 return 0;
306}
\No newline at end of file