Created
March 7, 2023 04:54
-
-
Save westc/c49c9f917c0e002218ba1dc630e6cc56 to your computer and use it in GitHub Desktop.
getPathsComparer() - Makes it possible to easily compare multiple nested objects. This was designed to easily be used in conjunction with Array.prototype.sort().
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Makes it possible to easily compare multiple nested objects. | |
* @param {...(number|string|(number|string)[])} paths | |
* The paths to the values within the 2 arguments passed to the returned | |
* function. The values at these paths will be compared. | |
* @returns | |
* A function which accepts 2 values that will be compared. | |
* | |
* @example | |
* console.log([ | |
* {first: 'Anne', last: 'Mayo', age: 25}, // becomes 2nd | |
* {first: 'Valeria', last: 'Andrade', age: 26}, // becomes 1st | |
* {first: 'Jerry', last: 'Mayo', age: 27}, // becomes 3rd | |
* ].sort(getPathsComparer('last', 'first'))); | |
* | |
* @example | |
* console.log([ | |
* {first: 'Greg', last: 'Sica', age: 25}, // becomes 2nd | |
* {first: 'Lindsay', last: 'Barbados', age: 26}, // becomes 3rd | |
* {first: 'Corey', last: 'Trent', age: 27}, // becomes 1st | |
* ].sort(getPathsComparer(['first'], ['last']))); | |
* | |
* @example | |
* console.log([ | |
* {first: 'Greg', last: 'Sica', grades: ['B', 'C']}, // becomes 3rd | |
* {first: 'Lindsay', last: 'Barbados', grades: ['A', 'B']}, // becomes 2nd | |
* {first: 'Corey', last: 'Trent', grades: ['C', 'A']}, // becomes 1st | |
* ].sort(getPathsComparer(['grades', -1]))); | |
*/ | |
function getPathsComparer(...paths) { | |
// Coerce each value within `paths` to an array. | |
paths = paths.map(p => Array.isArray(p) ? p : [p]); | |
// The paths comparer function that will be returned. | |
return function(a, b) { | |
// Loop through all of the paths. | |
for (const path of paths) { | |
// a1 and b1 will represent a and b or one of their descendants. | |
let a1 = a, b1 = b; | |
// Loop through each key of each path. | |
for (const key of path) { | |
// If a1 or b1 is null or undefined then break out. | |
if (a1 == null || b1 == null) break; | |
// If the key is a negative number count from the end of the array-like | |
// object to get the next values for a1 and b1. | |
if (key < 0 && 'number' === typeof key) { | |
a1 = a1[a1.length + key]; | |
b1 = b1[b1.length + key]; | |
} | |
// In all other cases just pull the value for `key`. | |
else { | |
a1 = a1[key]; | |
b1 = b1[key]; | |
} | |
} | |
// Do a comparison of a1 to b1 and if they are not the same return either | |
// -1 or 1. | |
const result = (a1 == null || b1 == null) | |
? a1 == b1 ? 0 : a1 == null ? -1 : 1 | |
: (a1 === b1 || (a1 !== a1 && b1 !== b1)) ? 0 : a1 < b1 ? -1 : 1; | |
if (result) return result; | |
} | |
return 0; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment