Last active
September 7, 2021 17:36
-
-
Save gchumillas/66eb1f9e1d47701ef4f08298199e978b to your computer and use it in GitHub Desktop.
Sort a list of objects by fields
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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