JavaScript Array Sort - In Depth (and some handy sort utilities)
September 27, 2020
This post describes JavaScript's array sort method with examples of arrays of values, arrays of objects and sorting an object by key. s
Simple Examples
Array.prototype.sort()
sorts an array in place (i.e., it mutates the original array).
Todo - default sort description
To sort numbers:
1const numbers = [4, 8, 2, 0]2numbers.sort()3console.log(numbers) // -> [0, 2, 4, 8]
To sort strings:
1const strings = ['c', 'd', 'b', 'a']2strings.sort()3console.log(strings) // -> ["a", "b", "c", "d"]
Todo - for custom sorts, objects or unique sort ordering. Visualisation diagram - number line: <- -1 0 +1 -> function mySort(firstItem, secondItem)
To sort objects you need to use a custom sort function.
The equivalent sort function for the 2 examples above is:
1function defaultSort(a, b) {2 if (a < b) {3 return -1 // A negative result moves `a` before `b` to a lower4 // array index.5 }67 if (b < a) {8 return 1 // A positive result moves `a` after `b` to a higher9 // array index.10 }1112 return 0 // A zero result leaves 'a' and 'b' in the same order,13 // relative to each other14 // (other array items might get sorted above them)15}
To use this sort function:
1const numbers = [4, 8, 2, 0]2numbers.sort(defaultSort)3console.log(numbers) // -> [0, 2, 4, 8]
With es6 you can simplify this sort function:
1const numbers = [4, 8, 2, 0]2numbers.sort((a, b) => a - b)3console.log(numbers) // -> [0, 2, 4, 8]
Sorting an Array of Objects by Property
Here is the array of objects we will be working with:
1const employees = [2 {3 name: 'Jane',4 salary: 20000,5 role: 'Programmer'6 },7 {8 name: 'Dave',9 salary: 25000,10 role: 'Programmer'11 },12 {13 name: 'Ben',14 salary: 10000,15 role: 'Programmer'16 },17 {18 name: 'Carol',19 salary: 50000,20 role: 'Manager'21 },22 {23 name: 'Bob',24 salary: 25000,25 role: 'Programmer'26 },27 {28 name: 'Alice',29 salary: 15000,30 role: 'Programmer'31 },32 {33 name: 'Carol',34 salary: 100000,35 role: 'CEO'36 },37 {38 name: 'Dave',39 salary: 20000,40 role: 'Programmer'41 }42]
You sort objects by property:
1function sortByName({name: a}, {name: b}) {2 if (a < b) {3 return -14 }56 if (b < a) {7 return 18 }910 return 011}1213employees.sort(sortByName)
You can generalise this to work for any properties:
1const sortByProp = (prop) => (a, b) => {2 if (a[prop] < b[prop]) {3 return -14 }56 if (b[prop] < a[prop]) {7 return 18 }910 return 011}
It can be used like this:
1const sortByName = sortByProp('name')23employees.sort(sortByName)
Sorting Objects by Multiple Properties
The trick is to apply subsequent sort criteria only when earlier sort criteria return '0', i.e., the previous sort criteria considered the items to be equal.
This can be done with a single sort function, but I find it much easier to use an order
function to compose the sort functions:
1const order = (...fns) => (...args) => {2 let res = 0, i = 0;3 while (4 fns[i] !== undefined &&5 (res = fns[i++](...args)) === 06 );78 return res9}1011const byName = sortByProp('name')12const bySalary = sortByProp('salary')13const byRole = sortByProp('role')1415employees.sort(16 order(17 byName,18 bySalary,19 byRole,20 )21)2223console.log(employees)
This code reads much easier and, if you wanted to change the order of the sort criteria, you simply swap the order of the functions:
1employees.sort(2 order(3 byRole,4 bySalary,5 byName,6 )7)
An added benefit is it makes it much easier to write individual unit tests for each tiny sort function!
Sorting Objects by Key
Finally, to sort an object by keys you use the Object.entries
and Object.fromEntries
methods.
1const fruits = {2 'oranges': {3 cost: .8,4 quantity: 35 },6 'bananas': {7 cost: .75,8 quantity: 59 },10 'apples': {11 cost: .5,12 quantity: 1013 }14}1516const sorted = Object.fromEntries(17 Object.entries(18 fruits19 ).sort(([key]) => key)20)2122console.log(sorted)
How does this work?
Object.entries(fruits)
returns an array of arrays. Each sub array contains two elements:key
andobject
:
1[2 ["oranges", {3 cost: 0.8,4 quantity: 35 }], ["bananas", {6 cost: 0.75,7 quantity: 58 }], ["apples", {9 cost: 0.5,10 quantity: 1011 }]12]
.sort(([key]) => key)
uses an es6 arrow function and destructuring to sort each array by the first element:key
Object.fromEntries
converts the "array of arrays" back to an object.