Skip to content

Instantly share code, notes, and snippets.

@monkpit
Last active January 11, 2022 22:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save monkpit/b8e04a77c89d12bd1217b0c3bbad55fc to your computer and use it in GitHub Desktop.
Save monkpit/b8e04a77c89d12bd1217b0c3bbad55fc to your computer and use it in GitHub Desktop.
Numeric Prop Sorter - given a prop and an optional callback (for when equal values will be sub-sorted), returns a function to be passed to Array.sort
/**
* Creates a sort function that will compare based upon a certain property in an object.
*
* @param {keyof T} prop - the property of the object to sort by
* @param [options.order] the order to sort - either 'asc' or 'desc'
* @param [options.callback] callback used as a tiebreaker when the property on both objects is equal.
* @returns A function to be passed to Array.sort();
*/
export const numericPropSort =
<P extends string, T extends Record<P | keyof T, number>>(
prop: P,
options?: {
order?: "asc" | "desc";
callback?: (a: T, b: T) => number;
}
) =>
(a: T, b: T): number => {
let { callback, order } = options ?? {};
order = order ?? "asc";
if (a[prop] > b[prop]) return order === "asc" ? 1 : -1;
if (a[prop] < b[prop]) return order === "asc" ? -1 : 1;
return callback ? callback(a, b) : 0;
};
import numericPropSort from './numericPropSort';
import faker from 'faker/locale/en_US';
interface Foo {
name: string;
data: string;
isValid: boolean;
index: number;
secondaryIndex: number;
tertiaryIndex: number;
};
const fooFactory = (): Foo => ({
name: faker.commerce.productName(),
data: faker.commerce.department(),
isValid: faker.datatype.boolean(),
index: faker.datatype.number(1),
secondaryIndex: faker.datatype.number(99),
tertiaryIndex: faker.datatype.number(99)
});
// create test arrays
const fooArray = new Array(4).fill(null).map(() => fooFactory());
const barArray = new Array(4).fill(null).map((_, i) => ({ index: Math.trunc(i/2), secondaryIndex: 10-i }));
const bazArray = new Array(4).fill(null).map((_, i) => ({ index: Math.trunc(i/2) }));
// create sorters
const subSorter = numericPropSort("secondaryIndex");
const reverseSubSorter = numericPropSort("secondaryIndex", { order: "desc" });
const fooSorter = numericPropSort("index", { callback: subSorter });
const reverseFooSorter = numericPropSort("index", {
callback: reverseSubSorter,
});
console.log('fooArray - Normal sorting');
console.table(fooArray.sort(fooSorter));
console.log('fooArray - Sort secondaryIndex in reverse');
console.table(fooArray.sort(reverseFooSorter));
console.log('barArray - Normal sorting');
console.table(barArray.sort(fooSorter));
console.log('barArray - Sort secondaryIndex in reverse');
console.table(barArray.sort(reverseFooSorter));
console.table(bazArray);
console.table(bazArray.sort(fooSorter));
// ^ this line has a compiler error since bazArray's elements
// do not contain both `index` and `secondaryIndex`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment