comparator-factory-factory
Create comparison functions to be used for sorting arrays.
This is a dedicated tiny library, not aiming at a framework.
Features
- Available for both Node.js and browsers (including IE 11)
- Function-based comparison value selection
- Property-path-based comparison value selection can be implemented easily
- Handling
undefined
,null
,NaN
as first or last - String collation using native
Intl.Collator
- Locale-specific collation
- Case order: case-insensitive / upper-first / lower-first
- Numeric collation such that "1" < "2" < "10"
- See Intl.Collator at MDN for details
- Chaining comparison functions
- Designed to share the comparison rule in the product;
Creating not a comparison function directly but a comparison function factory that may be shared - Lightweight (~1.7kB minified, ~0.7kB gzipped)
Install
via npm
$ npm install comparator-factory-factory
;// const comparatorFactoryFactory = require("comparator-factory-factory"); const comparing = ;;
via CDN
or for modern browsers:
Usage & Examples
const comparing = ; "A5" "A1" null "A3" "A10" "a3" "A7";// => ["A1", "A3", "a3", "A5", "A7", "A10", null] "A5" "A1" null "A3" "A10" "a3" "A7";// => [null, "A10", "A7", "A5", "a3", "A3", "A1"]
const users = id: "01" name: "Alice" profile: age: 17 id: "02" name: "Bob" id: "03" profile: age: 16 id: "04" name: "alice" profile: age: 15 id: "05" name: "bob" profile: age: 18 id: "06" name: "Bob" profile: age: 15 ; const comparing = ; users; // => [ // { id: "02", name: "Bob" }, // { id: "04", name: "alice", profile: { age: 15 } }, // { id: "06", name: "Bob", profile: { age: 15 } }, // { id: "03", profile: { age: 16 } }, // { id: "01", name: "Alice", profile: { age: 17 } }, // { id: "05", name: "bob", profile: { age: 18 } }, // ] const comparing1 = ; const comparing2 = ; users; // => [ // { id: "03", profile: { age: 16 } }, // { id: "06", name: "Bob", profile: { age: 15 } }, // { id: "05", name: "bob", profile: { age: 18 } }, // { id: "02", name: "Bob" }, // { id: "04", name: "alice", profile: { age: 15 } }, // { id: "01", name: "Alice", profile: { age: 17 } }, // ] const comparingPropertyPath = ; users; // => [ // { id: "02", name: "Bob" }, // { id: "04", name: "alice", profile: { age: 15 } }, // { id: "06", name: "Bob", profile: { age: 15 } }, // { id: "03", profile: { age: 16 } }, // { id: "01", name: "Alice", profile: { age: 17 } }, // { id: "05", name: "bob", profile: { age: 18 } }, // ]
API
Summary
// Create a comparison function factory based on the specified rule.const comparatorFactory = ; // Create a comparison function.const comparator = ; // Evaluate.// 0 if obj1 and obj2 are equal,// a negative number if obj1 is smaller,// a positive number if obj1 is larger.const comparisonResult = ; // Create a comparison function with reverse order.const reversedComparator = comparator; // Comparator itself.const comparatorItself = comparator; // Create a combined comparison function.// If comparator(obj1, obj2) is falsy, then evaluate specified comparison function.const combinedComparator = comparator;
comparatorFactoryFactory({ selector?, specials?, locales?, collator? }) => comparatorFactory
Create a comparison function factory based on the specified rule.
Parameters
-
selector: key => obj => comparisonResult
A function selecting comparison value from
key
andobj
.
The receiving parameterkey
is each argument ofcomparatorFactory(key1, key2, ...)
.
The receiving parameterobj
is each argument ofcomparator(obj1, obj2)
.
The default implementation is as follows.{tryreturn ;catchreturn undefined;}Following code is a property-path-based comparison example using lodash/get. (BTW, there are so many similar modules.)
const get = ;const comparingPropertyPath =;// for TypeScript:// const comparingPropertyPath = comparatorFactoryFactory<string>({// selector: key => obj => get(obj, key),// });const users =id: 1 profile: age: 18id: 2 profile: age: 15;users; -
specials: [[value1, "first" (or "last")], [value2, "first" (or "last")], ...]
Special values to place first or last.
The default value is as follows.undefined "first"null "first"NaN "first" -
collator: { locales?, sensitivity?, numeric?, caseFirst? } | { compare: (string1, string2) => number }
String comparison method.
Possible values are as follows.- An options object for
Intl.Collator
constructor with optional propertylocales
- An object that has
compare(string1, string2) => number
method (aIntl.Collator
instance does)
See Intl.Collator at MDN for details.
The default value is the defaultIntl.Collator()
. - An options object for
comparatorFactory(key1, key2, ...) => comparator
Create a comparison function.
Parameters
-
key1
,key2
, ...Comparison key passed to the
selector
option of the rule.
If the length of arguments is 0,obj
itself becomes the comparison value.
comparator(obj1, obj2) => number
Evaluate.
0 if obj1
and obj2
are considered to be equal,
a negative number if obj1
is considered to be smaller than obj2
,
a positive number if obj1
is considered to be larger than obj2
.
comparator.reversed(really? = true) => comparator
Create a comparison function with reverse order.
comparator.or((obj1, obj2) => number) => comparator
Create a combined comparison function.
The combined comparison function evaluates the original comparator(obj1, obj2)
first.
If that result equals to 0 (or falsy), it evaluates specified comparison function next.
Limitation
Array.prototype.sort()
always put the undefined
at the end of the array.
This behavior is specified in the ECMAScript specification.
const comparing = ; id: 3 id: 1 id: undefined id: 7 ;// => [{ id: undefined }, { id: 1 }, { id: 3 }, { id: 7 }]// As expected. 3 1 null 7;// => [null, 1, 3, 7]// As expected. 3 1 NaN 7;// => [NaN, 1, 3, 7]// As expected. 3 1 undefined 7;// => [1, 3, 7, undefined]// NOT as expected.// The expected result is [undefined, 1, 3, 7]// but `undefined` is always placed at the end...
License
WTFPL