some-common-functions-js 1.1.0 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -1
- package/README.md +125 -27
- package/index.js +122 -85
- package/package.json +1 -4
package/CHANGELOG.md
CHANGED
|
@@ -33,7 +33,15 @@ Improve README.md documentation.
|
|
|
33
33
|
## Version 1.0.9 - 2025/11/28 - ITA
|
|
34
34
|
- Provided more documentation in test.js to remind a developer how to symbolic-link (mimick as installed) the package and running the test code.
|
|
35
35
|
- Added new function, hasOnlyAll(), and updated the README.md documentation accordingly.
|
|
36
|
-
|
|
36
|
+
|
|
37
37
|
## Version 1.1.0 - 2025/12/22 - ITA
|
|
38
38
|
- Improved documentation.
|
|
39
39
|
- Moved in more functions to the package: `deepClone(anObject)`, `getSortedObject(anObject)`, `timeStampYyyyMmDd(dateInstance)` and `timeStampString(dateInstance)`.
|
|
40
|
+
|
|
41
|
+
## Version 1.1.1 - 2025/12/26 - ITA
|
|
42
|
+
- Removed lodash dependency and re-implemented the get() and set() object functions, reducing package size.
|
|
43
|
+
- Re-implemented the getSortedObj() function to no longer use the get() object function.
|
|
44
|
+
- Improved the duplicate removal process in getArrayWithNoDuplicates() function, so as to be more reliable across all cases. Implemented the new getNextDifferentObject() function in the light of that.
|
|
45
|
+
|
|
46
|
+
## Version 1.1.2 - 2025/12/26 - ITA
|
|
47
|
+
Corrected a minor error in the README documentation.
|
package/README.md
CHANGED
|
@@ -6,16 +6,18 @@ Common functions used for working with JavaScript objects and validating field v
|
|
|
6
6
|
## Installation
|
|
7
7
|
```
|
|
8
8
|
npm install some-common-functions-js
|
|
9
|
-
```
|
|
9
|
+
```
|
|
10
|
+
|
|
10
11
|
## 1. JavaScript Object Utilities
|
|
11
|
-
|
|
12
|
+
|
|
12
13
|
### `deepClone(anObject)`
|
|
13
|
-
Returns a deep clone of a plain Javascript object. The clone, while it has field equal to that of the original object, is separate from the original object.
|
|
14
|
-
|
|
14
|
+
Returns a deep clone of a plain Javascript object. The clone, while it has field equal to that of the original object, is separate from the original object.
|
|
15
|
+
|
|
15
16
|
### `getPaths(anObject)`
|
|
16
17
|
Returns a string array of path/field names inside a JavaScript object.
|
|
18
|
+
|
|
17
19
|
***Example***
|
|
18
|
-
```
|
|
20
|
+
```
|
|
19
21
|
const { getPaths } = require("some-common-functions-js");
|
|
20
22
|
let client = {
|
|
21
23
|
name: "Jack",
|
|
@@ -35,11 +37,14 @@ let client = {
|
|
|
35
37
|
let paths = getPaths(client);
|
|
36
38
|
// ["name", "surname", "address.streetNum", "address.streetName", "address.suburb",
|
|
37
39
|
// "address.town", "address.country.name", "address.country.code"]
|
|
38
|
-
```
|
|
40
|
+
```
|
|
41
|
+
|
|
39
42
|
### `getSortedObject(anObject)`
|
|
40
|
-
Returns an object with sorted fields,
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
Returns an object with sorted fields, ordered by field name ascending.
|
|
44
|
+
|
|
45
|
+
***Examples***
|
|
46
|
+
```
|
|
47
|
+
const { get } = require("common-functions-js");
|
|
43
48
|
const client = {
|
|
44
49
|
firstName: "Isaiah",
|
|
45
50
|
lastName: "Tshabalala",
|
|
@@ -74,11 +79,66 @@ const sortedObject = getSortedObject(client);
|
|
|
74
79
|
lastName: 'Tshabalala'
|
|
75
80
|
}
|
|
76
81
|
*/
|
|
77
|
-
```
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### `get(anObject, path)`
|
|
85
|
+
Returns the value of an object at the specified path.
|
|
86
|
+
Can take the place of lodash get() function.
|
|
87
|
+
|
|
88
|
+
***Examples***
|
|
89
|
+
```
|
|
90
|
+
const { get } = require("some-common-functions-js");
|
|
91
|
+
const client = {
|
|
92
|
+
firstName: "Isaiah",
|
|
93
|
+
lastName: "Tshabalala",
|
|
94
|
+
address: {
|
|
95
|
+
houseNum: "5520",
|
|
96
|
+
streetName: "Main Road",
|
|
97
|
+
mainPlace: "Evaton",
|
|
98
|
+
subPlace: "Evaton Small Farms",
|
|
99
|
+
city: "Vereeniging",
|
|
100
|
+
country: {
|
|
101
|
+
name: "South Africa",
|
|
102
|
+
code: "ZA"
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
let result = get(client, "address.country");
|
|
108
|
+
// { name: "South Africa", code: "ZA" }
|
|
109
|
+
|
|
110
|
+
result = get(client, "address.country.code");
|
|
111
|
+
// "ZA"
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### `set(anObject, path)`
|
|
115
|
+
Sets the value of an object at the specified path.
|
|
116
|
+
Can take the place of lodash set() function.
|
|
117
|
+
|
|
118
|
+
***Examples***
|
|
119
|
+
```
|
|
120
|
+
const { set } = require("some-common-functions-js");
|
|
121
|
+
|
|
122
|
+
let emptyObj = {};
|
|
123
|
+
set(emptyObj, "address.country.name", "South Africa");
|
|
124
|
+
set(emptyObj, "address.country.code", "ZA");
|
|
125
|
+
set(emptyObj, "firstName", "Isaiah");
|
|
126
|
+
set(emptyObj, "lastName", "Tshabalala");
|
|
127
|
+
console.log(emptyObj);
|
|
128
|
+
/*
|
|
129
|
+
{
|
|
130
|
+
address: { country: { name: 'South Africa', code: 'ZA' } },
|
|
131
|
+
firstName: 'Isaiah',
|
|
132
|
+
lastName: 'Tshabalala'
|
|
133
|
+
}
|
|
134
|
+
*/
|
|
135
|
+
```
|
|
136
|
+
|
|
78
137
|
### `hasOnly(anObject, ...fields)`
|
|
79
138
|
Returns `true` if the object contains **only** some or all of the specified fields and no others.
|
|
139
|
+
|
|
80
140
|
***Examples***
|
|
81
|
-
```
|
|
141
|
+
```
|
|
82
142
|
const { hasOnly } = require("some-common-functions-js");
|
|
83
143
|
|
|
84
144
|
let car = {
|
|
@@ -97,12 +157,14 @@ result = hasOnly(car, "maxSpeed", "gvm", "power");
|
|
|
97
157
|
|
|
98
158
|
result = hasOnly(car, "make", "model");
|
|
99
159
|
// false, because car has fields other than the specified fields.
|
|
100
|
-
```
|
|
160
|
+
```
|
|
161
|
+
|
|
101
162
|
### `hasAll(anObject, ...fields)`
|
|
102
163
|
Returns `true` if the object contains **all** the specified fields.
|
|
103
164
|
The object may contain additional fields.
|
|
165
|
+
|
|
104
166
|
***Examples***
|
|
105
|
-
```
|
|
167
|
+
```
|
|
106
168
|
const { hasAll } = require("some-common-functions-js");
|
|
107
169
|
let car = {
|
|
108
170
|
make: "Ford",
|
|
@@ -116,11 +178,13 @@ let result = hasAll(car, "make", "model");
|
|
|
116
178
|
|
|
117
179
|
let result = hasAll(car, "passengerCapacity", "year");
|
|
118
180
|
// false, because car does not have "passengerCapacity" field.
|
|
119
|
-
```
|
|
181
|
+
```
|
|
182
|
+
|
|
120
183
|
### `hasOnlyAll(anObject, ...fields)`
|
|
121
|
-
Return `true` if an object contains only all the specified fields, nothing more, nothing less
|
|
122
|
-
|
|
123
|
-
|
|
184
|
+
Return `true` if an object contains only all the specified fields, nothing more, nothing less
|
|
185
|
+
|
|
186
|
+
***Examples***
|
|
187
|
+
```
|
|
124
188
|
const { hasOnlyAll } = require("some-common-functions-js");
|
|
125
189
|
let car = {
|
|
126
190
|
make: "Ford",
|
|
@@ -327,20 +391,16 @@ console.log(objArray);
|
|
|
327
391
|
*/
|
|
328
392
|
let teams = [
|
|
329
393
|
{
|
|
330
|
-
score: 85,
|
|
331
|
-
numGames: 10
|
|
394
|
+
score: 85, numGames: 10
|
|
332
395
|
},
|
|
333
396
|
{
|
|
334
|
-
score: 90,
|
|
335
|
-
numGames: 12
|
|
397
|
+
score: 90, numGames: 12
|
|
336
398
|
},
|
|
337
399
|
{
|
|
338
|
-
score: 85,
|
|
339
|
-
numGames: 8
|
|
400
|
+
score: 85, numGames: 8
|
|
340
401
|
},
|
|
341
402
|
{
|
|
342
|
-
score: 90,
|
|
343
|
-
numGames: 10
|
|
403
|
+
score: 90, numGames: 10
|
|
344
404
|
}
|
|
345
405
|
];
|
|
346
406
|
// Using objCompare to sort fields where there are mixed sort directions.
|
|
@@ -396,7 +456,7 @@ Create an array of objects with duplicates eliminated. Taking only the first or
|
|
|
396
456
|
* The value of the comparison field must include both the field name and sort direction.
|
|
397
457
|
* Sort direction assumed to be "asc" if not provided.
|
|
398
458
|
* Examples of comparison fields: "firstName", "lastName desc", "address.province asc", "address.townOrCity".
|
|
399
|
-
|
|
459
|
+
|
|
400
460
|
***Example***
|
|
401
461
|
```
|
|
402
462
|
const { getObjArrayWithNoDuplicates } = require("some-common-functions-js");
|
|
@@ -424,7 +484,42 @@ console.log(noDuplicatesArray); // Should contain only unique objects according
|
|
|
424
484
|
{ score: 85, numGames: 10 }
|
|
425
485
|
]
|
|
426
486
|
*/
|
|
427
|
-
```
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
### `getNextDifferent(objArray, targetObj, startFrom, ...comparisonFields)`
|
|
490
|
+
Get the index in the array of objects, of the next element that is distinct from the target object.
|
|
491
|
+
Comparison fields must match the field & sort order of the object array.
|
|
492
|
+
Examples of comparison fields: "firstName", "lastName desc", "address.province asc", "address.townOrCity".
|
|
493
|
+
|
|
494
|
+
***Example***
|
|
495
|
+
```
|
|
496
|
+
const { getNextDifferentObj } = require("some-common-functions-js");
|
|
497
|
+
|
|
498
|
+
teamsArray = [
|
|
499
|
+
{ score: 90, numGames: 10 },
|
|
500
|
+
{ score: 90, numGames: 10 },
|
|
501
|
+
{ score: 90, numGames: 10 },
|
|
502
|
+
{ score: 90, numGames: 12 },
|
|
503
|
+
{ score: 90, numGames: 12 },
|
|
504
|
+
{ score: 90, numGames: 12 },
|
|
505
|
+
{ score: 85, numGames: 8 },
|
|
506
|
+
{ score: 85, numGames: 8 },
|
|
507
|
+
{ score: 85, numGames: 10 },
|
|
508
|
+
{ score: 85, numGames: 10 },
|
|
509
|
+
{ score: 85, numGames: 10 }
|
|
510
|
+
]; // Sorted by "score desc", "numGames asc".
|
|
511
|
+
|
|
512
|
+
let next = getNextDifferentObj(teamsArray, { score: 85, numGames: 8 }, 0, "score desc", "numGames asc");
|
|
513
|
+
// Throws an error because the startFrom index is to the left ('less than') the target object in terms of the field sort order.
|
|
514
|
+
|
|
515
|
+
next = getNextDifferentObj(teamsArray, { score: 90, numGames: 10 }, 0, "score desc", "numGames asc");
|
|
516
|
+
// 3
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
next = getNextDifferentObj(teamsArray, { score: 85, numGames: 10 }, 0, "score desc", "numGames asc");
|
|
520
|
+
// -1
|
|
521
|
+
```
|
|
522
|
+
|
|
428
523
|
## 4. Date Timestamp Functions
|
|
429
524
|
### `timeStampYyyyMmDd(dateInstance)`
|
|
430
525
|
Converts the date object to a string of the form CCYY-MM-DD
|
|
@@ -432,6 +527,9 @@ Converts the date object to a string of the form CCYY-MM-DD
|
|
|
432
527
|
### `timeStampString(dateInstance)`
|
|
433
528
|
Converts a date object to a string of the form CCYY-MM-DDThh:mm:ss.ccc, e.g. '2024-02-25T15:00:25.251'
|
|
434
529
|
|
|
530
|
+
### `addLeadingZeros(aNumber, newLength)`
|
|
531
|
+
Add leading zeros to a numerical string. E.g. addLeadingZeros(9, 3) = '009'
|
|
532
|
+
|
|
435
533
|
---
|
|
436
534
|
## License
|
|
437
535
|
MIT
|
package/index.js
CHANGED
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
* 2025/11/19 ITA 1.00 Genesis.
|
|
5
5
|
* 2025/11/28 ITA 1.01 Added function hasOnlyAll().
|
|
6
6
|
* 2025/12/22 ITA 1.02 Improved documentation of the functions and moved in more functions.
|
|
7
|
+
* 2025/12/30 ITA 1.03 Removed lodash dependency by re-implementing get() and set() object functions, significantly reducing this package size.
|
|
8
|
+
* Added function getNextDifferent() to deal better with duplicate removal from arrays of objects. * .
|
|
7
9
|
*/
|
|
8
|
-
const loDash = require('lodash');
|
|
9
10
|
|
|
10
11
|
/**Return true if userName is valid
|
|
11
12
|
* @param {string} userName
|
|
@@ -203,27 +204,87 @@ function getPaths(anObject) {
|
|
|
203
204
|
} // function getPaths()
|
|
204
205
|
module.exports.getPaths = getPaths;
|
|
205
206
|
|
|
206
|
-
/** Return an object with sorted fields,
|
|
207
|
+
/** Return an object with sorted fields, ordered by field name ascending.
|
|
207
208
|
* This is desirable when equality comparison is done to ensure two objects sharing equal field values
|
|
208
209
|
* the pass the equality test stringify(object1) === stringify(object2)
|
|
209
210
|
* @param {object} pObject
|
|
210
211
|
* @returns {object} an object with fields sorted in ascending order of field names.
|
|
211
212
|
*/
|
|
212
213
|
function getSortedObject(pObject) {
|
|
214
|
+
const objClone = deepClone(pObject);
|
|
215
|
+
const paths = [];
|
|
216
|
+
const sortedObject = {};
|
|
213
217
|
|
|
214
|
-
|
|
218
|
+
// Obtain the outermost fields and sort them.
|
|
219
|
+
for (let field in objClone) {
|
|
220
|
+
paths.push(field);
|
|
221
|
+
}
|
|
215
222
|
paths.sort();
|
|
216
|
-
const sortedObject = {};
|
|
217
223
|
|
|
224
|
+
// Assign the sorted fields to the new object.
|
|
218
225
|
for (let index in paths) {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
226
|
+
const field = paths[index];
|
|
227
|
+
if (Object.prototype.toString.call(objClone[field]) === '[object Object]') {
|
|
228
|
+
sortedObject[field] = getSortedObject(objClone[field]);
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
sortedObject[field] = objClone[field];
|
|
232
|
+
} //
|
|
233
|
+
} // for (let field in paths) {
|
|
234
|
+
|
|
223
235
|
return sortedObject;
|
|
224
236
|
} // function getSortedObject(pObject) {
|
|
225
237
|
module.exports.getSortedObject = getSortedObject;
|
|
226
238
|
|
|
239
|
+
/** Get the value of a field specified by the path from an object.
|
|
240
|
+
* @param {object} anObject a Javascript object.
|
|
241
|
+
* @param {string} path a path specifying the field whose value is to be obtained.
|
|
242
|
+
* @returns {*} the value of the field specified by the path.
|
|
243
|
+
*/
|
|
244
|
+
function get(anObject, path) {
|
|
245
|
+
if (getPaths(anObject).includes(path) === false) {
|
|
246
|
+
console.log(hasAll(anObject, path), path, anObject, getPaths(anObject));
|
|
247
|
+
throw new Error(`Path ${path} does not exist on the object.`);
|
|
248
|
+
}
|
|
249
|
+
let paths = path.split('.');
|
|
250
|
+
let currentObj = deepClone(anObject);
|
|
251
|
+
|
|
252
|
+
let value = currentObj[paths[0]];
|
|
253
|
+
if (paths.length > 1) {
|
|
254
|
+
paths.splice(0, 1);
|
|
255
|
+
return get(value, paths.join('.'));
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
return value;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
module.exports.get = get;
|
|
262
|
+
|
|
263
|
+
/** Set the value of a field specified by the path on an object.
|
|
264
|
+
* @param {object} anObject a Javascript object.
|
|
265
|
+
* @param {string} path a path specifying the field whose value is to be set.
|
|
266
|
+
* @param {*} value the value to set.
|
|
267
|
+
*/
|
|
268
|
+
function set(anObject, path, value) {
|
|
269
|
+
/*if (hasAll(anObject, path) === false) {
|
|
270
|
+
throw new Error(`Path ${path} does not exist on the object.`);
|
|
271
|
+
}*/
|
|
272
|
+
|
|
273
|
+
let paths = path.split('.');
|
|
274
|
+
if (paths.length > 1) {
|
|
275
|
+
if (!anObject[paths[0]]) {
|
|
276
|
+
anObject[paths[0]] = {};
|
|
277
|
+
}
|
|
278
|
+
const subObject = anObject[paths[0]];
|
|
279
|
+
paths.splice(0, 1);
|
|
280
|
+
set(subObject, paths.join('.'), value);
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
anObject[paths[0]] = value;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
module.exports.set = set;
|
|
287
|
+
|
|
227
288
|
/**
|
|
228
289
|
* Determine whether an object contains only 1, some or all of the specified fields, and not any other fields.
|
|
229
290
|
* @param {object} anObject a Javascript object.
|
|
@@ -393,6 +454,37 @@ function binarySearchObj(objArray, searchObj, startFrom = 0, ...sortFields) {
|
|
|
393
454
|
} // function binarySearchObj(objArray, searchObj, ...comparisonFields) {
|
|
394
455
|
module.exports.binarySearchObj = binarySearchObj;
|
|
395
456
|
|
|
457
|
+
/**Get the index of the first element in an object array that is different from the target element
|
|
458
|
+
* according to the comparison fields.
|
|
459
|
+
* @param {Array<object>} objArray an array of objects
|
|
460
|
+
* @param {object} targetObj target object
|
|
461
|
+
* @param {number} startFrom index from which to start searching
|
|
462
|
+
* @param {...string} comparisonFields comparison fields plus sort order.
|
|
463
|
+
* @returns index of the next different object.
|
|
464
|
+
*/
|
|
465
|
+
function getNextDifferent(objArray, targetObj, startFrom, ...comparisonFields) {
|
|
466
|
+
let start = startFrom,
|
|
467
|
+
end = objArray.length - 1;
|
|
468
|
+
|
|
469
|
+
// If target object is to the right of objArray[start], then throw an error..
|
|
470
|
+
if (objCompare(targetObj, objArray[start], ...comparisonFields) > 0)
|
|
471
|
+
throw new Error('targetObj is to the right (\'greater than\') objArray[startFrom].');
|
|
472
|
+
|
|
473
|
+
while (start < end) {
|
|
474
|
+
let mid = Math.trunc((start + end) / 2);
|
|
475
|
+
if (objCompare(targetObj, objArray[mid], ...comparisonFields) === 0) {
|
|
476
|
+
start = mid + 1;
|
|
477
|
+
}
|
|
478
|
+
else if (objCompare(targetObj, objArray[mid], ...comparisonFields) < 0) {
|
|
479
|
+
end = mid;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
if (objCompare(targetObj, objArray[start], ...comparisonFields) === 0)
|
|
483
|
+
return -1;
|
|
484
|
+
return start;
|
|
485
|
+
}
|
|
486
|
+
module.exports.getNextDifferent = getNextDifferent;
|
|
487
|
+
|
|
396
488
|
/**Create an array with duplicates eliminated, according to certain fields. Taking only the first or last object from each duplicate set.
|
|
397
489
|
* If firstOfDuplicates === true, then the first element in each set of duplicates is taken.
|
|
398
490
|
* if firstOfDuplicates === false, then the last element is taken from each set of duplicates.
|
|
@@ -407,89 +499,34 @@ module.exports.binarySearchObj = binarySearchObj;
|
|
|
407
499
|
* @returns {Array<object>} an array with no duplicates.
|
|
408
500
|
*/
|
|
409
501
|
function getObjArrayWithNoDuplicates(objArray, firstOfDuplicates, ...comparisonFields) {
|
|
410
|
-
function getNextSearchObj(pNext) {
|
|
411
|
-
const nextObj = {...objArray[next]};
|
|
412
|
-
let lastField;
|
|
413
|
-
if (comparisonFields.length > 0)
|
|
414
|
-
lastField = comparisonFields[comparisonFields.length - 1].split(' ');
|
|
415
|
-
else
|
|
416
|
-
throw new Error('Supply atleast 1 comparisonFields parameter.');
|
|
417
|
-
|
|
418
|
-
const lastFieldName = lastField[0];
|
|
419
|
-
const sortDir = lastField.length > 1? lastField[1] : 'asc';
|
|
420
|
-
const lastFieldValue = loDash.get(nextObj, lastFieldName);
|
|
421
|
-
|
|
422
|
-
if (typeof lastFieldValue === 'number') {
|
|
423
|
-
if (sortDir === 'asc')
|
|
424
|
-
loDash.set(nextObj, lastFieldName, 1e-10 + lastFieldValue);
|
|
425
|
-
else
|
|
426
|
-
loDash.set(nextObj, lastFieldName, -1e-10 + lastFieldValue);
|
|
427
|
-
}
|
|
428
|
-
else if (typeof lastFieldValue === 'string') { // instance of String
|
|
429
|
-
if (sortDir === 'asc')
|
|
430
|
-
loDash.set(nextObj, lastFieldName, lastFieldValue + ' ');
|
|
431
|
-
else
|
|
432
|
-
loDash.set(nextObj, lastFieldName, ' ' + lastFieldValue);
|
|
433
|
-
}
|
|
434
|
-
else if (lastFieldValue instanceof Date) {
|
|
435
|
-
if (sortDir === 'asc')
|
|
436
|
-
loDash.set(nextObj, lastFieldName, new Date(1 + lastFieldValue.getTime()));
|
|
437
|
-
else
|
|
438
|
-
loDash.set(nextObj, lastFieldName, new Date(-1 + lastFieldValue.getTime()));
|
|
439
|
-
}
|
|
440
|
-
else
|
|
441
|
-
throw new Error(`${lastFieldName} must be type Number, String or Date`);
|
|
442
|
-
|
|
443
|
-
return nextObj;
|
|
444
|
-
} // function getNextSearchObj(pNext)
|
|
445
502
|
|
|
446
503
|
if (objArray.length <= 1)
|
|
447
504
|
return [...objArray];
|
|
448
505
|
|
|
449
|
-
if (
|
|
450
|
-
throw new Error(`firstOfDuplicates must be
|
|
506
|
+
if (typeof firstOfDuplicates !== 'boolean')
|
|
507
|
+
throw new Error(`firstOfDuplicates must be boolean true or false.`);
|
|
451
508
|
|
|
452
509
|
const noDuplicates = [];
|
|
453
|
-
|
|
454
|
-
let
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
}
|
|
459
|
-
nextSearchObj = getNextSearchObj(objArray[next]);
|
|
460
|
-
|
|
461
|
-
while (next < objArray.length) {
|
|
462
|
-
// The aim is to jump to the next element that is not a duplicate of objArray[next].
|
|
463
|
-
next = binarySearchObj(objArray, nextSearchObj, next, ...comparisonFields);
|
|
464
|
-
let comparison = objCompare(objArray[next], nextSearchObj, ...comparisonFields);
|
|
465
|
-
if (comparison < 0) {
|
|
466
|
-
if (firstOfDuplicates) {
|
|
467
|
-
next++;
|
|
468
|
-
if (next < objArray.length) {
|
|
469
|
-
noDuplicates.push(objArray[next]);
|
|
470
|
-
nextSearchObj = getNextSearchObj(objArray[next]);
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
else {
|
|
474
|
-
noDuplicates.push(objArray[next]);
|
|
475
|
-
next++;
|
|
476
|
-
if (next < objArray.length)
|
|
477
|
-
nextSearchObj = getNextSearchObj(objArray[next]);
|
|
478
|
-
}
|
|
479
|
-
continue;
|
|
510
|
+
let idx;
|
|
511
|
+
let grpStart = 0; // Start index of current duplicate group.
|
|
512
|
+
while (grpStart < objArray.length - 1) {
|
|
513
|
+
if (firstOfDuplicates) {
|
|
514
|
+
noDuplicates.push(objArray[grpStart]);
|
|
480
515
|
}
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
516
|
+
|
|
517
|
+
grpStart = getNextDifferent(objArray, objArray[grpStart], grpStart + 1, ...comparisonFields);
|
|
518
|
+
if (grpStart < 0)
|
|
519
|
+
break; // No more different objects.
|
|
520
|
+
|
|
521
|
+
let grpEnd = grpStart - 1;
|
|
522
|
+
if (!firstOfDuplicates) {
|
|
523
|
+
noDuplicates.push(objArray[grpEnd]);
|
|
488
524
|
}
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
525
|
+
idx = grpStart;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
if (objCompare(objArray[idx], noDuplicates[noDuplicates.length - 1], ...comparisonFields) !== 0)
|
|
529
|
+
noDuplicates.push(objArray[idx]); // Add the last object.
|
|
493
530
|
|
|
494
531
|
return noDuplicates;
|
|
495
532
|
} // function getObjArrayWithNoDuplicates(objArray, ...comparisonFields) {
|
|
@@ -519,8 +556,8 @@ function objCompare(obj1, obj2, ...comparisonFields) {
|
|
|
519
556
|
if (!sortDirections.includes(sortDir))
|
|
520
557
|
throw new Error('Sort direction must be one of ' + sortDirections.toString());
|
|
521
558
|
|
|
522
|
-
const value1 =
|
|
523
|
-
const value2 =
|
|
559
|
+
const value1 = get(obj1, fieldName);
|
|
560
|
+
const value2 = get(obj2, fieldName);
|
|
524
561
|
|
|
525
562
|
const returnValue = (sortDir === 'desc'? -1: 1);
|
|
526
563
|
if (value1 > value2)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "some-common-functions-js",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "Common functions used with Javascript objects, and field validation functions.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"validation",
|
|
@@ -36,8 +36,5 @@
|
|
|
36
36
|
"main": "index.js",
|
|
37
37
|
"scripts": {
|
|
38
38
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
39
|
-
},
|
|
40
|
-
"dependencies": {
|
|
41
|
-
"lodash": "^4.17.21"
|
|
42
39
|
}
|
|
43
40
|
}
|