My favorite sorting algorithm.
A Pen by Gerald Fullam on CodePen.
| <table id="t1"></table> | |
| <table id="t2"></table> | |
| <table id="t3"></table> | |
| <table id="t4"></table> |
| /* "Sort by, then by" | |
| // Based on this jsfiddle: | |
| // http://jsfiddle.net/dFNva/1/ | |
| // as a response to this stackoverflow post: | |
| // http://stackoverflow.com/a/979325/2502532 | |
| // Improvements include JSON deep access with path notation, 'then by' sorting. | |
| // Description: Sort by object key, with optional reverse ordering, priming, and 'then by' sorting. | |
| // Usage: | |
| array.sort( | |
| by(path[, reverse[, primer[, then]]]) | |
| ); | |
| // Examples: | |
| // Sort by 'props.title', Ascending [A-Z]: | |
| array.sort(by('props.title')); | |
| // Sort by 'props.title', Descending [Z-A]: | |
| array.sort(by('props.title'), true); | |
| // Sort by 'props.title', Ascending [A-Z], Primer function converts strings to uppercase for case-insensitive comparison: | |
| array.sort( | |
| by('props.title', false, function (x) { return x.toUpperCase() }) | |
| ); | |
| // Sort by 'id', Descending [9-0] (reverse), Primer `parseFloat` converts to number before comparison; | |
| // Then by 'props.title', Descending [Z-A], Primer function converts strings to uppercase for case-insensitive comparison: | |
| // NOTE: sort order is inherited; setting to true in the secondary `by()` would return the reverse of the parent `by()` sort order. | |
| array.sort( | |
| by('id', true, parseFloat, | |
| by('props.title', false, function (x) { return x.toUpperCase() }) | |
| ) | |
| ); | |
| */ | |
| /* THE FUNCTION */ | |
| var by = function (path, reverse, primer, then) { | |
| // Light weight json deep access | |
| var get = function (obj, path) { | |
| if (path) { | |
| path = path.split('.'); | |
| for (var i = 0, len = path.length - 1; i < len; i++) { | |
| obj = obj[path[i]]; | |
| }; | |
| return obj[path[len]]; | |
| } | |
| return obj; | |
| }, | |
| // Invokes primer function if provided | |
| prime = function (obj) { | |
| return primer ? primer(get(obj, path)) : get(obj, path); | |
| }; | |
| // Actual sorting function to be returned to native .sort method | |
| return function (a, b) { | |
| var A = prime(a), | |
| B = prime(b); | |
| return ( | |
| (A < B) ? -1 : | |
| (A > B) ? 1 : | |
| // If A == B, then sort by supplemental 'by' function received as 'then' | |
| (typeof then === 'function') ? then(a, b) : 0 | |
| ) * [1,-1][+!!reverse]; | |
| }; | |
| }; | |
| /* THE ARRAY */ | |
| var places = [ | |
| { | |
| "id": 0, | |
| "props": { | |
| "city": "Dallas", | |
| "state": "TX", | |
| "zip": 75001 | |
| } | |
| }, { | |
| "id": 1, | |
| "props": { | |
| "city": "Austin", | |
| "state": "TX", | |
| "zip": 78610 | |
| } | |
| }, { | |
| "id": 2, | |
| "props": { | |
| "city": "Beverly Hills", | |
| "state": "CA", | |
| "zip": 90210 | |
| } | |
| }, { | |
| "id": 3, | |
| "props": { | |
| "city": "Houston", | |
| "state": "TX", | |
| "zip": 77002 | |
| } | |
| }, { | |
| "id": 4, | |
| "props": { | |
| "city": "New York", | |
| "state": "NY", | |
| "zip": 10453 | |
| } | |
| }, { | |
| "id": 4, | |
| "props": { | |
| "city": "O'Neill", | |
| "state": "NE", | |
| "zip": 68763 | |
| } | |
| }, { | |
| "id": 4, | |
| "props": { | |
| "city": "Omaha", | |
| "state": "NE", | |
| "zip": 68183 | |
| } | |
| } | |
| ]; | |
| /* THE EXAMPLES */ | |
| /* Sort by "state" A-Z */ | |
| places.sort(by('props.state')); | |
| // Output | |
| var t1 = document.getElementById('t1'); | |
| t1.innerHTML += '<caption>Sort by "state" A-Z</caption>'; | |
| for (var i = 0; i < places.length; i++) { | |
| t1.innerHTML += '<tr><td>' + places[i].props.city + '</td><td class="sortby">' + places[i].props.state + '</td><td> ' + places[i].props.zip + '</td></tr>'; | |
| } | |
| /* Sort by "state" Z-A (reverse) */ | |
| places.sort(by('props.state', true)); | |
| // Output | |
| var t2 = document.getElementById('t2'); | |
| t2.innerHTML += '<caption>Sort by "state" Z-A (reverse)</caption>'; | |
| for (var i = 0; i < places.length; i++) { | |
| t2.innerHTML += '<tr><td>' + places[i].props.city + '</td><td class="sortby">' + places[i].props.state + '</td><td> ' + places[i].props.zip + '</td></tr>'; | |
| } | |
| /* Sort by 'state', Descending [Z-A] (reverse), Primer `parseFloat` converts to number before comparison; | |
| // Then by 'zip', Descending [9-0], Primer function converts strings to uppercase before comparison. | |
| // NOTE: sort order is inherited; setting to true here would return the reverse of the parent sort order. */ | |
| places.sort( | |
| by('props.state', true, null, | |
| by('props.zip', false, parseFloat) | |
| ) | |
| ); | |
| // Output | |
| var t3 = document.getElementById('t3'); | |
| t3.innerHTML += '<caption>Sort by "state" Z-A (reverse), then by "ZIP" 9-0 (reverse inherited, primer)</caption>'; | |
| for (i = 0; i < places.length; i++) { | |
| t3.innerHTML += '<tr><td>' + places[i].props.city + '</td><td class="sortby">' + places[i].props.state + '</td><td class="thenby"> ' + places[i].props.zip + '</td></tr>'; | |
| } | |
| /* Sort by 'city', Ascending [A-Z], Primer function converts strings to uppercase & removes non-word characters before comparison. */ | |
| places.sort( | |
| by('props.city', false, function (x) { | |
| return x.toUpperCase().replace(/\W/g, ''); | |
| }) | |
| ); | |
| // Output | |
| var t4 = document.getElementById('t4'); | |
| t4.innerHTML += '<caption>Sort by "city" A-Z, case- & punctuation-insensitive (primer)</caption>'; | |
| for (i = 0; i < places.length; i++) { | |
| t4.innerHTML += '<tr><td class="sortby">' + places[i].props.city + '</td><td>' + places[i].props.state + '</td><td> ' + places[i].props.zip + '</td></tr>'; | |
| } |
My favorite sorting algorithm.
A Pen by Gerald Fullam on CodePen.
| html { font: normal 62.5% Arial, sans-serif; } | |
| body { padding: 10px; } | |
| table { | |
| table-layout: fixed; | |
| border-collapse: collapse; | |
| font-size: 1.3em; | |
| margin-bottom: 18px; | |
| width: 100%; | |
| border: none; | |
| } | |
| table caption { | |
| text-align: left; | |
| font-weight: bold; | |
| font-size: 1.5rem; | |
| } | |
| table td { | |
| color: #999; | |
| padding: 9px; | |
| vertical-align: middle; | |
| text-align: left; | |
| line-height: 1em; | |
| border-bottom: 1px solid #bcbec0; | |
| } | |
| table .number { | |
| text-align: center; | |
| } | |
| .sortby { | |
| color: #333; | |
| font-weight: bold; | |
| } | |
| .thenby { | |
| color: #333; | |
| } |