Created
September 2, 2015 06:01
-
-
Save farandal/f07d48f797a9e1384095 to your computer and use it in GitHub Desktop.
Javascript Merge Sorting implementation, sortBy, and sortByFields helpers
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
/** | |
* Merge Sorting | |
* | |
* //Sorting by efault comparator using merge sorting. | |
* util.sort(array); | |
* //specify a comparator: | |
* var sortOrder = -1; | |
* util.sort(array,function(a,b) { return ((_a < _b) ? -1 : (_a > _b) ? 1 : 0) * sortOrder; }); | |
* | |
* //Sort by field | |
* | |
* //return the array ordered by firstName ascending. | |
* util.sortBy(array,"FirstName"); | |
* //return the array ordered by firstName lenghts. | |
* util.sortBy(array,"FirstName",function(val) { return val.length; }); | |
* parseInt as the wrapper for Age attribute comparission. | |
* util.sortBy(array,"Age", parseInt); | |
* //specify a custom wrapper | |
* util.sortBy(array,"Age", function(val) { return yourFn(val) }); | |
* return the results in inverse order | |
* util.sortBy(array,"-Age", function(val) { return yourFn(val) }); | |
* | |
* //Sorting by multiple fields; | |
* //return the array ordered by age, and then for Firstname in inverse order. | |
* util.sortByFields(array,["Age","-FirstName"]); | |
* //return the array ordered by Firstname Z-A and then for Lastname A-Z | |
* util.sortByFields(array,["-Firstname","LastName"]); | |
* //add a wrapper to order the results by the length of the FirstName, then the length of the LastName | |
* util.sortByFields(array,["-Firstname","LastName"],function(val) { return val.length; }); | |
* | |
**/ | |
// Setup sample data: | |
var array = [{ | |
FirstName: "Zach", | |
LastName: "Emergency", | |
Age: 35 | |
}, { | |
FirstName: "Nancy", | |
LastName: "Nurse", | |
Age: 27 | |
}, { | |
FirstName: "Ethel", | |
LastName: "Emergency", | |
Age: 42 | |
}, { | |
FirstName: "Nina", | |
LastName: "Nurse", | |
Age: 48 | |
}, { | |
FirstName: "Anthony", | |
LastName: "Emergency", | |
Age: 44 | |
}, { | |
FirstName: "Nina", | |
LastName: "Nurse", | |
Age: 32 | |
}, { | |
FirstName: "Ed", | |
LastName: "Emergency", | |
Age: 28 | |
}, { | |
FirstName: "Peter", | |
LastName: "Physician", | |
Age: 58 | |
}, { | |
FirstName: "Al", | |
LastName: "Emergency", | |
Age: 51 | |
}, { | |
FirstName: "Ruth", | |
LastName: "Registration", | |
Age: 62 | |
}, { | |
FirstName: "Ed", | |
LastName: "Emergency", | |
Age: 38 | |
}, { | |
FirstName: "Tammy", | |
LastName: "Triage", | |
Age: 29 | |
}, { | |
FirstName: "Alan", | |
LastName: "Emergency", | |
Age: 60 | |
}, { | |
FirstName: "Nina", | |
LastName: "Nurse", | |
Age: 54 | |
}]; | |
var util = {}; | |
/** | |
* Merge sort implementation | |
* Divide and Conquer! :) | |
* http://en.wikipedia.org/wiki/Merge_sort | |
* @param {Array} arr | |
* @param {Function} comparator | |
* @return {Array} | |
*/ | |
util.sort = function (arr, comparator) { | |
var mid, left, right; | |
if (arr.length < 2) { | |
return arr; | |
} | |
if (!comparator) { | |
comparator = defaultComparator; | |
} | |
function defaultComparator(a, b) { | |
return a < b ? -1 : (a > b ? 1 : 0); | |
} | |
function merge(left, right, comparator) { | |
var result = []; | |
while (left.length && right.length) { | |
if (comparator(left[0], right[0]) <= 0) { | |
// if 0 it should preserve same order (stable) | |
result.push(left.shift()); | |
} else { | |
result.push(right.shift()); | |
} | |
} | |
if (left.length) { | |
result.push.apply(result, left); | |
} | |
if (right.length) { | |
result.push.apply(result, right); | |
} | |
return result; | |
} | |
mid = Math.round(arr.length / 2); | |
left = util.sort(arr.slice(0, mid), comparator); | |
right = util.sort(arr.slice(mid, arr.length), comparator); | |
return merge(left, right, comparator); | |
} | |
/** | |
* sortBy allows the caller to sort an object array by one of its properties. | |
* The default comparator will order items in ascending order. | |
* If a minus sign is placed at the beginning of the 'field' argument, | |
* the array will be sorted in descending order. | |
* | |
* @example | |
* //returns the array ordered by Age property descending. | |
* array = util.sortBy(array,"-Age"); | |
* | |
* Optionally, a custom comparator function can be passed as an argument for this function. | |
* Optionally, a custom property wrapper function can be passed as an argument, which will convert the property value before comparison is performed. | |
* @param {Array} arr object array to be sorted] | |
* @param {String} field field string] | |
* @param {Function} comparator custom comparator] | |
* @param {Function} wrapper function to convert the property value before performing the comparission. | |
* @return {Array} | |
*/ | |
util.sortBy = function (array, field, wrapper, comparator) { | |
var reverse = 1, | |
key; | |
if (typeof field !== "string") { | |
throw "Field parameter must be a string"; | |
} | |
if (field[0] === "-") { | |
reverse = -1; | |
field = field.substr(1); | |
}; | |
if (wrapper && typeof wrapper === "function") { | |
key = function (x) { | |
return wrapper(x[field]); | |
}; | |
} else { | |
key = function (x) { | |
return x[field]; | |
}; | |
} | |
if (!comparator) { | |
comparator = function (a, b) { | |
a = key(a); | |
b = key(b); | |
return reverse * ((a > b) - (b > a)); | |
}; | |
} | |
return util.sort(array, comparator); | |
}; | |
/** | |
* sortByFields Allows the caller to sort an array by multiple fields | |
* | |
* @example: | |
* //returns the sorted array by Age property, prior to applying a parseInt on Age property before performing the comparission. | |
* //and sort in descending order (reversed). | |
* sortByFields(arr,["-Age"],parseInt); | |
* | |
* @param {Array} array Array to be sorted | |
* @param {Array} fields field list to be sorted e.g: ["FirstName","-Age"] | |
* @param {Function} wrapper optional wrapper function, if you need to convert the property value before performing the comparission. note: apply for all fields. ] | |
* @return {Array} | |
*/ | |
util.sortByFields = function (array, fields, wrapper) { | |
function _sortByAttr(attr) { | |
var sortOrder = 1; | |
if (attr[0] === "-") { | |
sortOrder = -1; | |
attr = attr.substr(1); | |
}; | |
return function (a, b) { | |
var _a = a[attr], | |
_b = b[attr], | |
result; | |
if (typeof wrapper === "function") { | |
_a = wrapper(a[attr]); | |
_b = wrapper(b[attr]); | |
} | |
return ((_a < _b) ? -1 : (_a > _b) ? 1 : 0) * sortOrder; | |
} | |
} | |
function _getSortFunc() { | |
return function (a, b) { | |
for (var result = 0, i = 0; result === 0 && i < fields.length; i++) { | |
result = _sortByAttr(fields[i])(a, b); | |
} | |
return result; | |
} | |
} | |
return util.sort(array, _getSortFunc.apply(null, fields)); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
It doesn't work for me with +/-. I call
console.log(util.sortByFields(array,["+Age"], parseInt));
and saw:But just
console.log(util.sortByFields(array,["Age"], parseInt));
works fine