Skip to content

Instantly share code, notes, and snippets.

@gchumillas
Last active September 7, 2021 17:36
Show Gist options
  • Save gchumillas/66eb1f9e1d47701ef4f08298199e978b to your computer and use it in GitHub Desktop.
Save gchumillas/66eb1f9e1d47701ef4f08298199e978b to your computer and use it in GitHub Desktop.
Sort a list of objects by fields
/**
* Sorts a list list of records by fields.
*
*
* Example 1:
*
* const items = [
* { currency: 'EUR', amount: 101.45 },
* { currency: 'EUR', amount: 33.23 },
* { currency: 'EUR', amount: 55.00 },
* { currency: 'USD', amount: 77.48 },
* { currency: 'USD', amount: 88.75 }
* ]
*
* // sorts items by currency (ascending) and amount (descending)
* console.log(sort(items, { currency: 1, amount: -1 }))
*
*
* Example 2:
*
* const items = [
* { name: 'John Smith', sex: 'male' },
* { name: 'Olivia Smith', sex: 'female' },
* { name: 'Federica Sanchez', sex: 'female' },
* { name: 'Paco Hernandez', sex: 'male' },
* ]
*
* // sorts items by sex (descending, use a custom comparator) and name (ascending)
* console.log(sort(items, { sex: -1, name: 1 }, [{
* cols: ['sex'], test: ({ item0, item1 }) => {
* const { sex: sex0 } = item0
* const { sex: sex1 } = item1
*
* if (sex0 == 'male' && sex1 == 'female') {
* return -1 // male is lower than female (please, this is just an example)
* } else if (sex0 == 'female' && sex1 == 'male') {
* return +1 // female is greater than male (pleeease, don't try to get absurd conclusions)
* }
*
* return 0
* }
* }]))
*/
export const sort = <
R extends Record<string, any>,
S extends Record<string, number>,
T extends (params: { item0: R, item1: R, order: S, col: string }) => number
>(
items: R[],
order: S,
tests: { cols: string[], test: T }[] = []
) => {
// transforms the filters into an object for better performance
const testMap: Record<string, T> = tests.reduce((prev, curr) => {
const { cols, test } = curr
const tests = cols.reduce((prev, curr) => ({ ...prev, [curr]: test }), {})
return { ...prev, ...tests }
}, {})
const cols = Object.keys(order)
return items.sort((item0, item1) => cols
.map((col) => {
const test = testMap[col]
return test
? order[col] * test({ item0, item1, order, col })
: item0[col] > item1[col] ? order[col] : item0[col] < item1[col] ? -order[col] : 0
})
.reduce((prev, cur) => (prev ? prev : cur), 0)
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment