├── .editorconfig ├── README.md ├── index.js ├── package.json └── test ├── mocha.opts └── tests.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | # Tab indent, JS style 8 | [*] 9 | end_of_line = lf 10 | insert_final_newline = true 11 | indent_size = 2 12 | indent_style = tab 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Common functions for array.sort(), to keep your code neat and tidy 2 | 3 | Tired of staring at the same array.sort() (also known as [Array.prototype.sort()](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/sort) ) functions over and over again? 4 | 5 | Worried about stuff like Unicode comparisons? 6 | 7 | Need to sort an array of objects by some nested key, using a particular sort function? 8 | 9 | Want to do cool stuff like compare domain names, ordering subdomains beneath their parents? 10 | 11 | Use the `sorts` module! 12 | 13 | ## Using the module 14 | 15 | var sorts = require('sorts') 16 | 17 | ## alphabetical 18 | 19 | Sorts by alphabetical order, case insensitive, handles unicode. 20 | 21 | Given: 22 | 23 | var fruits = ['pineapple', 'mango', 'coconut'] 24 | 25 | Just: 26 | 27 | fruits.sort(sorts.alphabetical) 28 | 29 | Returns: 30 | 31 | ['coconut', 'mango', 'pineapple'] 32 | 33 | ## byLength 34 | 35 | Given: 36 | 37 | var fruits = ['pineapple', 'mango', 'coconut'] 38 | 39 | Returns: 40 | 41 | ['mango', 'coconut', 'pineapple'] 42 | 43 | 44 | Just: 45 | 46 | fruits.sort(sorts.byLength) 47 | 48 | ## byNumber(keyName) 49 | ## numeric(keyName) 50 | 51 | var ages = [21, 8, 20] 52 | 53 | Just: 54 | 55 | ages.sort(sorts.numeric) 56 | 57 | Returns: 58 | 59 | [8, 20, 21] 60 | 61 | ## domainName 62 | 63 | Sort alphabetically, but order subdomains beneath their parents, and include 'www.' immediately after the regular domain name. Eg: 64 | 65 | var domainNames = [ 66 | 'banana.com', 67 | 'www.banana.com', 68 | 'peach.com', 69 | 'yolo.swag.banana.com', 70 | 'pear.com', 71 | 'www.pear.com', 72 | 'www.bananameltdown.com', 73 | 'swag.banana.com', 74 | 'bananameltdown.com', 75 | 'www.peach.com' 76 | ] 77 | domainNames.sort(sorts.domainName) 78 | 79 | Returns: 80 | 81 | [ 82 | 'banana.com', 83 | 'www.banana.com', 84 | 'swag.banana.com', 85 | 'yolo.swag.banana.com', 86 | 'bananameltdown.com', 87 | 'www.bananameltdown.com', 88 | 'peach.com', 89 | 'www.peach.com', 90 | 'pear.com', 91 | 'www.pear.com' 92 | ] 93 | 94 | ## byKey(keyName, sortFunction) 95 | 96 | Sort an array of objects by a specified key. `sortFunction` can be any of the sort functions above - `alphabetical` is the default `sortFunction`. 97 | 98 | var customers = [{ 99 | name: 'Joe', 100 | age: 35, 101 | }, { 102 | name: 'Alex', 103 | age: 28 104 | }] 105 | 106 | Just: 107 | 108 | customers.sort(sorts.byKey('name', 'alphabetical')) 109 | 110 | Returns: 111 | 112 | [{ 113 | name: 'Alex', 114 | age: 28 115 | },{ 116 | name: 'Joe', 117 | age: 35, 118 | }] 119 | 120 | # Please add more sorts! 121 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var log = console.log.bind(console); 2 | 3 | var prototypeOf = function(object){ 4 | return Object.prototype.toString.call(object).split(' ')[1].slice(0, 6) 5 | } 6 | 7 | var normalizeWww = function(domainName){ 8 | return domainName.split('www.').reverse()[0] 9 | } 10 | 11 | var reverseDomainName = function(domainName){ 12 | return domainName.split('.').reverse().join('.') 13 | } 14 | 15 | // These are inside a var as other sorts use them! 16 | var sorts = { 17 | byLength: function (a, b) { 18 | return a.length - b.length 19 | }, 20 | 21 | byNumber: function(a,b) { 22 | return a - b; 23 | }, 24 | 25 | alphabetical: function(a,b){ 26 | if ( prototypeOf(a) !== 'String' || prototypeOf(b) !== 'String' ) { 27 | log('Warning:', a, 'is not a string') 28 | return false; 29 | } 30 | return a.localeCompare(b); 31 | }, 32 | 33 | domainName: function(a,b){ 34 | if ( prototypeOf(a) !== 'String' || prototypeOf(b) !== 'String' ) { 35 | log('Warning:', a, 'is not a string') 36 | return false; 37 | } 38 | var aWasWww = a.startsWith('www.'); 39 | var bWasWww = b.startsWith('www.'); 40 | a = normalizeWww(a); 41 | b = normalizeWww(b); 42 | // Eg, we are comparing www.foo.com to foo.com 43 | if ( a === b && aWasWww !== bWasWww) { 44 | return aWasWww ? 1 : -1; 45 | } 46 | 47 | // Let's reverse the domain names 48 | a = reverseDomainName(a) 49 | b = reverseDomainName(b) 50 | return a.localeCompare(b); 51 | } 52 | } 53 | 54 | var alphabetical = function(a,b){ 55 | if ( prototypeOf(a) !== 'String' ) { 56 | log('Warning:', a, 'is not a string') 57 | return false; 58 | } 59 | return a.localeCompare(b); 60 | } 61 | 62 | var byKey = function(property, sortName){ 63 | return function(a,b) { 64 | var sortFunction = sorts[sortName] 65 | if ( ! sortFunction ) { 66 | sortFunction = sorts.alphabetical 67 | } 68 | return sortFunction(a[property], b[property]) 69 | } 70 | } 71 | 72 | module.exports = { 73 | byLength: sorts.byLength, 74 | byNumber: sorts.byNumber, 75 | byKey, 76 | domainName: sorts.domainName, 77 | alphabetical: sorts.alphabetical, 78 | 79 | // Aliases 80 | numeric: sorts.byNumber 81 | } 82 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sorts", 3 | "version": "1.1.1", 4 | "author": { 5 | "email": "mike.maccana@gmail.com", 6 | "name": "Mike MacCana" 7 | }, 8 | "bugs": { 9 | "url": "https://github.com/mikemaccana/sorts/issues" 10 | }, 11 | "dependencies": {}, 12 | "description": "Common functions for array.sort()", 13 | "devDependencies": {}, 14 | "homepage": "https://github.com/mikemaccana/sorts#readme", 15 | "keywords": [ 16 | "algorithms", 17 | "array", 18 | "sort", 19 | "sorting" 20 | ], 21 | "license": "MIT", 22 | "main": "index.js", 23 | "maintainers": [ 24 | { 25 | "name": "mikemaccana", 26 | "email": "mike.maccana@gmail.com" 27 | } 28 | ], 29 | "optionalDependencies": {}, 30 | "repository": { 31 | "type": "git", 32 | "url": "git+https://github.com/mikemaccana/sorts.git" 33 | }, 34 | "scripts": { 35 | "test": "mocha" 36 | }, 37 | "browserify": { 38 | "transform": [ 39 | "brfs", 40 | [ 41 | "babelify", 42 | { 43 | "presets": ["es2015"] 44 | } 45 | ] 46 | ] 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --ui tdd 2 | --bail 3 | -------------------------------------------------------------------------------- /test/tests.js: -------------------------------------------------------------------------------- 1 | // Tests. Mocha TDD/assert style. See 2 | // http://visionmedia.github.com/mocha/ 3 | // http://nodejs.org/docs/latest/api/assert.html 4 | 5 | var sorts = require('../index.js') 6 | 7 | var assert = require('assert') 8 | 9 | var log = console.log.bind(console) 10 | 11 | suite('Correctly sorts', function(){ 12 | 13 | test('alphabetical', function(){ 14 | var fruits = ['pineapple', 'mango', 'coconut'] 15 | fruits.sort(sorts.alphabetical) 16 | var expected = [ 'coconut', 'mango', 'pineapple' ] 17 | assert.deepEqual(fruits, expected) 18 | }); 19 | 20 | test('length', function(){ 21 | var fruits = ['pineapple', 'mango', 'coconut'] 22 | fruits.sort(sorts.byLength) 23 | var expected = ['mango', 'coconut', 'pineapple'] 24 | assert.deepEqual(fruits, expected) 25 | }); 26 | 27 | test('numeric', function(){ 28 | var ages = [21, 8, 20] 29 | ages.sort(sorts.numeric) 30 | var expected = [8, 20, 21] 31 | assert.deepEqual(ages, expected) 32 | }); 33 | 34 | test('numeric', function(){ 35 | var customers = [{ 36 | name: 'Joe', 37 | age: 35, 38 | }, { 39 | name: 'Alex', 40 | age: 28 41 | }] 42 | customers.sort(sorts.byKey('name', 'alphabetical')) 43 | var expected = [{ 44 | name: 'Alex', 45 | age: 28 46 | }, { 47 | name: 'Joe', 48 | age: 35, 49 | }] 50 | assert.deepEqual(customers, expected) 51 | }); 52 | 53 | test('domainNames', function(){ 54 | var domainNames = [ 55 | 'banana.com', 56 | 'www.banana.com', 57 | 'peach.com', 58 | 'pear.com', 59 | 'www.pear.com', 60 | 'www.bananameltdown.com', 61 | 'bananameltdown.com', 62 | 'www.peach.com', 63 | 'yolo.swag.banana.com', 64 | 'swag.banana.com' 65 | ] 66 | domainNames.sort(sorts.domainName) 67 | var expected = [ 68 | 'banana.com', 69 | 'www.banana.com', 70 | 'swag.banana.com', 71 | 'yolo.swag.banana.com', 72 | 'bananameltdown.com', 73 | 'www.bananameltdown.com', 74 | 'peach.com', 75 | 'www.peach.com', 76 | 'pear.com', 77 | 'www.pear.com' 78 | ] 79 | assert.deepEqual(domainNames, expected) 80 | }) 81 | 82 | }) 83 | --------------------------------------------------------------------------------