Skip to content

Instantly share code, notes, and snippets.

@malko
Last active July 19, 2017 13:01
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 malko/06745377a82d3cbda2b9 to your computer and use it in GitHub Desktop.
Save malko/06745377a82d3cbda2b9 to your computer and use it in GitHub Desktop.
make a multiple fields comparator for sort functions
/**
* return a comparator to use in Array.sort method context.
* take a list of properties (array or string delimited by pipe or comma) which you want to use for sort
* @param {(string|string[])) fields list of properties names (array or string delimited by pipe or comma) which you want to use for sort
* each field name may be prefixed by an < or > to sort on ascending or descending order
* you can use n< or n> as prefix for a natural order sorting
* @returns {function(object, object)}
*/
function propertyComparator(compareConfig) {
if (typeof compareConfig === 'string') {
compareConfig = compareConfig.split(/[|,]/);
}
let propertyName = compareConfig.shift();
let isDescending = false;
let isNatural = false;
const next = compareConfig.length ? propertyComparator(compareConfig) : () => 0;
const [comparatorConfig, naturalFlag, orderSymbol] = propertyName.match(/^(n?)(<|>)/) || ['', '', ''];
if (comparatorConfig) {
naturalFlag === 'n' && (isNatural = true);
orderSymbol === '>' && (isDescending = true);
propertyName = propertyName.slice(comparatorConfig.length);
}
const comparator = propertyComparator[isNatural ? 'createNaturalComparator' : 'createBasicComparator'](propertyName);
if (isDescending) {
return (a, b) => comparator(b, a) || next(a, b);
}
return (a, b) => comparator(a, b) || next(a, b);
}
/**
* create a basic comparator between two objects based on given property name
* @param {string} propertyName name of the property used for comparison
* @returns {function(object, object)}
*/
propertyComparator.prototype.createBasicComparator = (propertyName) => {
return (a, b) => {
if (a[propertyName] > b[propertyName]) {
return 1;
}
return a[propertyName] < b[propertyName] ? -1 : 0;
};
};
/**
* create a natural comparator between two objects based on given property name
* @param {string} propertyName name of the property used for comparison
* @returns {function(object, object)}
*/
propertyComparator.prototype.createNaturalComparator = (fieldName) => {
if (String.prototype.localeCompare) {
return (a, b) => a[fieldName].localeCompare(b[fieldName], undefined, { numeric: true });
} else {
return propertyComparator.createBasicComparator(fieldName);
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment