Last active
May 13, 2021 15:50
-
-
Save wcarss/9cf19134b815af2d25d091291b688654 to your computer and use it in GitHub Desktop.
a toy function to sort js arrays with sql-like syntax
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
// preamble: public domain; no warranty | |
// | |
// this is a toy -- it is slow, cannot handle unicode, keys w/ | |
// spaces, nested keys, natural ordering, etc. | |
// orderBy('key1 [asc|1|desc|-1][, key2 [asc|1|desc|-1]][, etc]') | |
// | |
// write sql-like sort orders for arrays of objects, e.g.: | |
// | |
// arr.sort(orderBy('some_key desc, other_key asc'); | |
// arr.sort(orderBy('some_key, other_key asc')); | |
// arr.sort(orderBy('a_key asc, b_key desc, c_key')); | |
// | |
// After reading some complicated sort functions, I wanted | |
// to quickly write something simple for 90% of our needs, | |
// just to see it. | |
// | |
// The key premise here is that the `cmp` function below can | |
// be chained to perform sorting by x, then y, then z, etc., | |
// added to some string+array manip and default handling. | |
// the cmp function, aka the spaceship operator <=> | |
// (credit to https://stackoverflow.com/a/9175783) | |
const cmp = (a, b) => { | |
if (a > b) { | |
return 1; | |
} else if (a < b) { | |
return -1; | |
} else { | |
return 0; | |
} | |
}; | |
// the actual function that would be exported | |
const orderBy = sortspec => { | |
// handle just asc/desc out front for convenience | |
if (sortspec.toLowerCase() === 'desc') { | |
return (a, b) => cmp(b, a); | |
} else if (sortspec.toLowerCase() === 'asc') { | |
return (a, b) => cmp(a, b); | |
} | |
// split string up into array of 1 or 2 element arrays | |
const sorts = sortspec.split(',').map(sort => sort.trim().split(' ')); | |
return (a, b) => sorts.reduce((acc, sort) => { | |
// accepts values asc, 1, desc, and -1 for orders | |
// defaults to ascending if order is invalid or not provided, | |
// sorting on an invalid key just hits undefined, preserves order | |
// also: no nested-key support! | |
const isAsc = sort.length === 1 || sort[1] === '1' || sort[1].toLowerCase() !== 'desc' && sort[1] !== '-1'; | |
const left = isAsc ? a : b; | |
const right = isAsc ? b : a; | |
// progressively apply sorts; this won't exit asap | |
return acc || cmp(left[sort[0]], right[sort[0]]); | |
}, null); | |
}; | |
// some example data to sort by: | |
const users = [ | |
{ | |
original_order: 0, | |
caseid: 'both empty', | |
some_prop: '', | |
fullname: '', | |
}, | |
{ | |
original_order: 1, | |
caseid: 'just empty name', | |
some_prop: 'test prop', | |
fullname: '', | |
}, | |
{ | |
original_order: 2, | |
caseid: 'empty prop name z', | |
some_prop: '', | |
fullname: 'empty prop test name z', | |
}, | |
{ | |
original_order: 3, | |
caseid: 'empty prop name a', | |
some_prop: '', | |
fullname: 'empty prop test name a', | |
}, | |
{ | |
original_order: 4, | |
caseid: 'same prop name b', | |
some_prop: 'test prop', | |
fullname: 'same prop test name b', | |
}, | |
{ | |
original_order: 5, | |
caseid: 'same prop name a', | |
some_prop: 'test prop', | |
fullname: 'same prop test name a', | |
}, | |
{ | |
original_order: 6, | |
caseid: 'prop + empty name', | |
some_prop: 'test prop', | |
fullname: '', | |
}, | |
{ | |
original_order: 7, | |
caseid: 'same prop name a again', | |
some_prop: 'test prop', | |
fullname: 'same prop test name a', | |
}, | |
{ | |
original_order: 8, | |
caseid: 'diff prop name b', | |
some_prop: 'other prop', | |
fullname: 'other prop test name b', | |
}, | |
{ | |
original_order: 9, | |
caseid: 'diff prop name a', | |
some_prop: 'other prop', | |
fullname: 'other prop test name a', | |
}, | |
{ | |
original_order: 9, | |
caseid: 'same prop test name a w/ unique prop', | |
some_prop: 'unique prop', | |
fullname: 'same prop test name a', | |
}, | |
]; | |
// some examples calls on the example data: | |
console.log( | |
'by undefined key (order should be preserved):', | |
[...users.sort(orderBy('count asc'))] | |
); | |
console.log( | |
'by some_prop descending, then by fullname', | |
[...users.sort(orderBy('some_prop desc, fullname'))] | |
); | |
console.log( | |
'by fullname ascending (note some_prop not ordered)', | |
[...users.sort(orderBy('fullname'))] | |
); | |
console.log( | |
'by fullname ascending, then by some_prop ascending', | |
[...users.sort(orderBy('fullname asc, some_prop asc'))] | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment