From 262db91f5f69800b68aa760781d0d9173ff3f495 Mon Sep 17 00:00:00 2001 From: Benedikt Franke Date: Mon, 24 Jun 2024 10:37:41 +0200 Subject: [PATCH 1/2] feat: add makeNumberCompareFn --- src/array.test.ts | 28 ++++++++++++++++++++++++++++ src/array.ts | 19 ++++++++++++++++++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/array.test.ts b/src/array.test.ts index b622ba4..83c93b0 100644 --- a/src/array.test.ts +++ b/src/array.test.ts @@ -11,6 +11,7 @@ import { sortByArray, toggleElement, withoutIndex, + makeNumberCompareFn, } from './array'; import { Maybe } from './types'; @@ -229,6 +230,33 @@ describe('makeStringCompareFn', () => { }); }); +describe('makeNumberCompareFn', () => { + it('creates a compare function that sorts numbers', () => { + type MaybeKeyNumber = { key?: Maybe }; + const compareFn = makeNumberCompareFn( + (record) => record.key, + ); + const original: Array = [ + { key: 3 }, + { key: 0 }, + { key: undefined }, + { key: 1 }, + { key: null }, + { key: 2 }, + {}, + ]; + expect(original.sort(compareFn)).toEqual([ + { key: 0 }, + { key: undefined }, + { key: null }, + {}, + { key: 1 }, + { key: 2 }, + { key: 3 }, + ]); + }); +}); + describe('localeCompareStrings', () => { it('sorts strings', () => { const original: Array = ['c', '', 'a', 'b']; diff --git a/src/array.ts b/src/array.ts index 6bc69fc..a981c50 100644 --- a/src/array.ts +++ b/src/array.ts @@ -93,7 +93,7 @@ export function sortByArray( } /** - * Takes a function that maps the values to sort and returns a compare function + * Takes a function that maps the values to sort to strings and returns a compare function * using `String.prototype.localeCompare`, usable in `Array.toSorted` or similar APIs. * * null, undefined and the empty string are not distinguished and first in sort order. @@ -109,6 +109,23 @@ export function makeStringCompareFn( }; } +/** + * Takes a function that maps the values to sort to numbers and returns a compare function + * using subtraction, usable in `Array.toSorted` or similar APIs. + * + * null, undefined and 0 are not distinguished and first in sort order. + */ +export function makeNumberCompareFn( + map: (sortable: TSortable) => Maybe, +): (a: TSortable, b: TSortable) => number { + return (a, b) => { + const mappedA = map(a) ?? 0; + const mappedB = map(b) ?? 0; + + return mappedA - mappedB; + }; +} + /** * Returns a compare function for values that are string, null or undefined, * using `String.prototype.localeCompare`, usable in `Array.toSorted` or similar APIs. From 7ebed43d51fafd7180043746474d144ce99bdff5 Mon Sep 17 00:00:00 2001 From: Benedikt Franke Date: Mon, 24 Jun 2024 10:44:59 +0200 Subject: [PATCH 2/2] accepts different fallback values --- src/array.test.ts | 28 +++++++++++++++++++++++++++- src/array.ts | 7 ++++--- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/array.test.ts b/src/array.test.ts index 83c93b0..4b8eb57 100644 --- a/src/array.test.ts +++ b/src/array.test.ts @@ -231,8 +231,9 @@ describe('makeStringCompareFn', () => { }); describe('makeNumberCompareFn', () => { + type MaybeKeyNumber = { key?: Maybe }; + it('creates a compare function that sorts numbers', () => { - type MaybeKeyNumber = { key?: Maybe }; const compareFn = makeNumberCompareFn( (record) => record.key, ); @@ -255,6 +256,31 @@ describe('makeNumberCompareFn', () => { { key: 3 }, ]); }); + + it('accepts different fallback values', () => { + const compareFn = makeNumberCompareFn( + (record) => record.key, + 9001, + ); + const original: Array = [ + { key: 3 }, + { key: 0 }, + { key: undefined }, + { key: 1 }, + { key: null }, + { key: 2 }, + {}, + ]; + expect(original.sort(compareFn)).toEqual([ + { key: 0 }, + { key: 1 }, + { key: 2 }, + { key: 3 }, + { key: undefined }, + { key: null }, + {}, + ]); + }); }); describe('localeCompareStrings', () => { diff --git a/src/array.ts b/src/array.ts index a981c50..ec3265f 100644 --- a/src/array.ts +++ b/src/array.ts @@ -113,14 +113,15 @@ export function makeStringCompareFn( * Takes a function that maps the values to sort to numbers and returns a compare function * using subtraction, usable in `Array.toSorted` or similar APIs. * - * null, undefined and 0 are not distinguished and first in sort order. + * null and undefined are coalesced to `fallbackValue`, by default 0, and thus not distinguished and first in sort order. */ export function makeNumberCompareFn( map: (sortable: TSortable) => Maybe, + fallbackValue: number = 0, ): (a: TSortable, b: TSortable) => number { return (a, b) => { - const mappedA = map(a) ?? 0; - const mappedB = map(b) ?? 0; + const mappedA = map(a) ?? fallbackValue; + const mappedB = map(b) ?? fallbackValue; return mappedA - mappedB; };