
Security News
Oxlint Introduces Type-Aware Linting Preview
Oxlint’s new preview brings type-aware linting powered by typescript-go, combining advanced TypeScript rules with native-speed performance.
comparator-factory-factory
Advanced tools
Create comparison functions to be used for sorting arrays.
This is a dedicated tiny library, not aiming at a framework.
undefined
, null
, NaN
as first or lastIntl.Collator
$ npm install comparator-factory-factory
import comparatorFactoryFactory from "comparator-factory-factory";
// const comparatorFactoryFactory = require("comparator-factory-factory");
const comparing = comparatorFactoryFactory();
[].sort(comparing());
<script src="https://cdn.jsdelivr.net/npm/comparator-factory-factory@0.2.0"></script>
<script>
const comparing = comparatorFactoryFactory();
[].sort(comparing());
</script>
or for modern browsers:
<script type="module">
import comparatorFactoryFactory from "https://cdn.jsdelivr.net/npm/comparator-factory-factory@0.2.0/index.min.mjs";
const comparing = comparatorFactoryFactory();
[].sort(comparing());
</script>
const comparing = comparatorFactoryFactory({
specials: [[null, "last"]],
collator: { caseFirst: "upper", numeric: true },
});
["A5", "A1", null, "A3", "A10", "a3", "A7"].sort(comparing());
// => ["A1", "A3", "a3", "A5", "A7", "A10", null]
["A5", "A1", null, "A3", "A10", "a3", "A7"].sort(comparing().reversed());
// => [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 = comparatorFactoryFactory();
users.sort(comparing(x => [x.profile.age, x.id]));
// => [
// { 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 = comparatorFactoryFactory({
specials: [[undefined, "last"]],
collator: { sensitivity: "base" },
});
const comparing2 = comparatorFactoryFactory({
specials: [[undefined, "last"]],
});
users.sort(
comparing1(x => x.name)
.reversed()
.or(comparing2(x => x.profile.age))
.or(comparing2(x => x.id))
);
// => [
// { 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 = comparatorFactoryFactory({
selector(fullpath) {
const paths = fullpath.replace(/\[(\d+)]/g, ".$1").split(".").filter(Boolean);
return obj => paths.every(path => (obj = obj[path]) != null) && obj;
},
});
users.sort(comparingPropertyPath("profile.age", "id"));
// => [
// { 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 } },
// ]
}
// Create a comparison function factory based on the specified rule.
const comparatorFactory = comparatorFactoryFactory({
selector: key => obj => comparisonResult,
specials: [
[undefined, "first"],
[null, "first"],
[NaN, "first"], // array with 2 elements: [0] value to treat specially, [1] "first" / "last"
],
collator: {
locales: undefined, // a BCP 47 language tag, or an array of such strings
sensitivity: "variant", // "base" / "accent" / "case" / "variant"
numeric: false,
caseFirst: "false", // "upper" / "lower" / "false" (use the locale's default)
},
});
// Create a comparison function.
const comparator = comparatorFactory(key1, key2, ...);
// Evaluate.
// 0 if obj1 and obj2 are equal, a negative number if obj1 is smaller, a positive number if obj1 is larger.
const comparisonResult = comparator(obj1, obj2);
// Create a comparison function with reverse order.
const reversedComparator = comparator.reversed();
// Comparator itself.
const comparatorItself = comparator.reversed(false);
// Create a combined comparison function.
// If comparator(obj1, obj2) === 0 (or falsy), then evaluate specified comparison function.
const combinedComparator = comparator.or((obj1, obj2) => number);
Create a comparison function factory based on the specified rule.
selector: key => obj => comparisonResult
A function selecting comparison value from key
and obj
.
The receiving parameter key
is each argument of comparatorFactory(key1, key2, ...)
.
The receiving parameter obj
is each argument of comparator(obj1, obj2)
.
The default implementation is as follows.
key => obj => {
try {
return key(obj);
} catch {
return undefined;
}
}
Following code is a property-path-based comparison example using lodash/get. (BTW, there are so many similar modules.)
const get = require("lodash/get");
const comparingPropertyPath = comparatorFactoryFactory({ selector: key => obj => get(obj, key) });
// for TypeScript:
// const comparingPropertyPath = comparatorFactoryFactory<string>({ selector: key => obj => get(obj, key) });
const users = [
{ id: 1, profile: { age: 18 } },
{ id: 2, profile: { age: 15 } },
];
users.sort(comparingPropertyPath("profile.age", "id"));
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.
Intl.Collator
constructor with optional property locales
compare(string1, string2) => number
method
Intl.Collator
instances have the compare(string1, string2) => number
methodSee Intl.Collator at MDN for details.
The default value is the default Intl.Collator()
.
Create a comparison function.
key1
, key2
, ...
Comparison key passed to the selector
option of the rule.
If the length of arguments is 0, obj
itself becomes the key
.
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
.
Create a comparison function with reverse order.
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.
Array.prototype.sort()
always put the undefined
at the end of the array.
This behavior is specified in the ECMAScript specification.
const comparing = comparatorFactoryFactory({ specials: [[undefined, "first"], [null, "first"], [NaN, "first"]] });
[{ id: 3 }, { id: 1 }, { id: undefined }, { id: 7 }].sort(comparing(x => x.id));
// => [{ id: undefined }, { id: 1 }, { id: 3 }, { id: 7 }]
// As expected.
[3, 1, null, 7].sort(comparing());
// => [null, 1, 3, 7]
// As expected.
[3, 1, NaN, 7].sort(comparing());
// => [NaN, 1, 3, 7]
// As expected.
[3, 1, undefined, 7].sort(comparing());
// => [1, 3, 7, undefined]
// NOT as expected.
// The expected result is [undefined, 1, 3, 7] but `undefined` is always placed at the end...
WTFPL
FAQs
Create comparison functions to be used for sorting arrays.
The npm package comparator-factory-factory receives a total of 4 weekly downloads. As such, comparator-factory-factory popularity was classified as not popular.
We found that comparator-factory-factory demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Oxlint’s new preview brings type-aware linting powered by typescript-go, combining advanced TypeScript rules with native-speed performance.
Security News
A new site reviews software projects to reveal if they’re truly FOSS, making complex licensing and distribution models easy to understand.
Security News
Astral unveils pyx, a Python-native package registry in beta, designed to speed installs, enhance security, and integrate deeply with uv.