1 | ;
|
2 |
|
3 | Object.defineProperty(exports, "__esModule", {
|
4 | value: true
|
5 | });
|
6 | exports.createCompareNatural = void 0;
|
7 |
|
8 | var _javascriptNaturalSort = _interopRequireDefault(require("javascript-natural-sort"));
|
9 |
|
10 | var _is = require("../../utils/is.js");
|
11 |
|
12 | var _factory = require("../../utils/factory.js");
|
13 |
|
14 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
|
15 |
|
16 | var name = 'compareNatural';
|
17 | var dependencies = ['typed', 'compare'];
|
18 | var 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 |
|
286 | exports.createCompareNatural = createCompareNatural;
|
287 |
|
288 | function 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 |