Skip to content

Instantly share code, notes, and snippets.

@westc
Last active October 28, 2025 15:27
Show Gist options
  • Select an option

  • Save westc/0fa192d75838f9323046c9b39ec79f2f to your computer and use it in GitHub Desktop.

Select an option

Save westc/0fa192d75838f9323046c9b39ec79f2f to your computer and use it in GitHub Desktop.
order() - Sorts an array based on one or more criteria.
/**
* A getter that produces the value to compare for a given item.
*
* @template T
* @callback order__Getter
* @param {T} item The current item from the array.
* @param {number} index The index of the current item.
* @param {T[]} array The entire array being ordered.
* @param {number} criterionIndex The index of the current criterion.
* @returns {number|string|bigint|boolean|Date} A value that can be ordered with < and >.
*/
/**
* An object form of a sorting criterion.
*
* @template T
* @typedef {Object} order__CriterionObject
* @property {order__Getter<T>} getter Function producing a comparable value for an item.
* @property {boolean} [reverse=false] Sort descending if true (ascending by default).
*/
/**
* Order an array by one or more criteria. Each criterion can be a getter function or
* an object containing `{ getter, reverse }`. When a plain function is supplied, it is
* treated as `{ getter: fn, reverse: false }` (ascending).
*
* @template T
* @param {T[]} array The array to order.
* @param {...(order__Getter<T> | order__CriterionObject<T>)} criterion One or more criteria to apply, in precedence order.
* @returns {T[]} A new array ordered by the provided criteria.
*/
function order(array, ...criterion) {
const criterionCount = criterion.length;
return array.map((item, index) => ({
item,
criterion: criterion.map((criteria, cIndex) => {
criteria = typeof criteria === 'function' ? {getter: criteria, reverse: false} : criteria;
return {
value: criteria.getter(item, index, array, cIndex),
reverse: !!criteria.reverse
};
})
}))
.sort((a, b) => {
for (let i = 0; i < criterionCount; i++) {
const {value: aCritValue, reverse} = a.criterion[i];
const bCritValue = b.criterion[i].value;
if (aCritValue < bCritValue) {
return reverse ? 1 : -1;
}
else if (aCritValue > bCritValue) {
return reverse ? -1 : 1;
}
}
return 0;
})
.map(x => x.item);
}
console.log(
order(
[
{firstName: 'Chris', lastName: 'West'},
{firstName: 'Chris', lastName: 'Brown'},
{firstName: 'Chris', lastName: 'Hemsworth'},
{firstName: 'Kim', lastName: 'Kardashian'},
{firstName: 'Gregorio', lastName: 'Arancibia'},
],
entry => entry.firstName,
{getter: entry => entry.lastName, reverse: true},
)
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment