Array sort( ) method and comparator in Javascript
Javascript sort( ) is an in-built method that can be used to sort an array. It is one of the higher order methods. This means that this method accepts certain functions as its argument.
There are a few important features of this method. You must know them to sort efficiently and without any logical mistakes in your code.
- It sorts the array elements in ascending order by default.
- It does not return a new array. It modifies the original array itself to its sorted form.
- It casts all the array elements as strings and then sorts them based on UTF-16 code unit values of the first character in the string.
- It accepts a comparator function as an argument. Custom logic can be written within the comparator function to sort the array based on different kinds of criteria.
- 5. It performs a stable sort.
Lets understand each of these features by experimenting with the sort( ).
Open your favourite editor and start coding and master the sort( ) within minutes!
It sorts the array elements in ascending order by default
When the sort method is applied on an array of letters or strings, it sorts the array elements in alphabetical order.
const arr = [‘m’, ‘a’, ‘c’, ‘b’]
arr.sort( )
console.log(arr)
//Expected output: [‘a’, ‘b’, ‘c’, ‘m’]
It can also sort numbers in ascending order. But this is of use only if the numbers are single digit values.
Note: Do not use sort( ) on numbers with digits 2 or more. You will see why in the coming features.
const arr = [1, 8, 2, 9]
arr.sort( )
console.log(arr)
//Expected output : [1, 2, 8, 9]
It modifies the original array itself
The sort method sorts the array elements in-place, that is within the array itself. It does not return a new sorted array. The same array is modified.
const arr = [1, 8, 2, 9]
console.log(arr)
arr.sort()
console.log(arr)
//Expected Output:
[1, 8, 2, 9]
[1, 2, 8, 9]
As you can see the sort method modified the original array.
It sorts the array based on the UTF-16 code unit values (unicode)
In javascript, all characters have a certain code, including numbers and alphabets.
You can use a method called charCodeAt( ) to find the unicode of a particular character.
For example,
const arr = [1, 100, 4, 6]
arr.sort( )
console.log(arr)
The ascending order of the elements is arr is 1, 4, 6, 100. But, sort( ) instead returns
[1, 100, 4, 6]
This is because sort( ) casts all the array elements as strings and compares the first character of the elements.
Since the first character of 1 and 100 are the same, they will have the same unicode values. Therefore 100 is not sorted to the end of the array.
const words = [ ‘water’ , ‘air’ , ‘earth’]
You can find the unicode values of w, a, e which are used by the sort function internally to compare.
console.log(words[0].charCodeAt(0)) // output: 119
console.log(words[1].charCodeAt(0)) // output: 97
console.log(words[2].charCodeAt(0)) // output: 101
Therefore the array is sorted as 97, 101, 119 , which is nothing but
[‘air’, ‘earth’, ‘water’]
It accepts a comparator as an argument
A comparator is a function that compares two values and determines the sorting order of the two values. The comparator can be customised to sort strings and object properties as well. Lets see how.
Syntax:
array.sort(comparator)
The comparator must be given two arguments to compare the elements of the array, two at a time. Say a , b.
It helps to sort the array based on three types of return values. This is also called as Three Way Comparison.
Negative
Positive
Zero
< 0
> 0
=== 0
If the return value is negative, a is sorted before b.
That is, the order would be a,b.
If the return value is positive, b is sorted before a.
That is, the order would be b,a.
If the return value is zero, a and b will remain in the same positions.
Essentially, the comparator can be written in the following form -
function comparator(a, b) {
If ( a < b ) {
return -1}
If ( a > b ) {
return 1}
return 0; //if a === b
}
This can be simplified to just one statement
function comparator(a,b) {
return a — b
}
If a-b is negative , then it means that a < b, so a will come before b in the sorting order.
If a-b is positive, then it means that a > b, so b will come before a in the sorting order.
If a-b is zero, then it means that a === b, so a and b remain in their positions.
Now lets see how to use comparator to sort different kinds of arrays.
Sorting a numeric array
const num = [1, 100, 6, 10]
num.sort(function(a,b){
console.log(a,b)
// You can check a and b values at each iteration and understand how sort works
return a — b
})
Output :
100 1
6 100
6 100
6 1
10 6
10 100
[1, 6, 10, 100]
Note : a and b get initialized to the second and first element of the array respectively.
Similarly if you want to get an array sorted in descending order, all you have to do is
num.sort(function(a,b){
return b — a
})
Sorting an array of strings
Suppose you have an array that you want to sort alphabetically and it is of the following form,
const abc = [‘B’ , ‘a’, ‘C’]
If you apply sort to this,
abc.sort( )
You will get this output
[‘B’, ‘C’, ‘a’]
This is because the unicode values of capital B and C are smaller than small a.
To overcome this, you can use the method toUpperCase( ). This capitalizes all the characters. To keep the original characters unchanged in the array, store the capitalized letters in a different variable in the function.
abc.sort(function(a,b){
let x = a.toUpperCase( )
let y = b.toUpperCase( )
if(x < y){
return -1
}
if (x > y){
return 1
}
return 0;
})
Output :
[‘a’, ‘B’, ‘C’ ]
Note: You cannot reduce the code to ‘return x — y’ for string comparisons. Subtracting two strings does not give a numeric value.
Sometimes it becomes necessary to sort an array of strings based on the length of the string. You can use the .length property on the string to find the length of the string.
const words = [‘shoe’, ‘sneakers’, ‘tie’]
words.sort(function(a, b){
return a.length-b.length
})
Output :
[‘tie’, ‘shoe’, ‘sneakers’]
Sorting object property values
If you apply sort( ) directly to an array of objects, it does nothing to the array. The object however, could have properties that need to be sorted. You have to access the properties with the dot notation in the comparator to sort them.
const obj = [ { name: ‘Rahul’, age: 21}, {name:’Shama’, age:22}, {name:’Mohit’, age:’19’}]
Lets sort this array of objects in ascending order of the age property.
obj.sort(function(a,b){
return a.age-b.age
})
Output:
[
{ name: ‘Mohit’, age: ‘19’ },
{ name: ‘Rahul’, age: 21 },
{ name: ‘Shama’, age: 22 }
]
It performs a stable sort
Suppose you have an array of objects with two properties, name and age.
const info = [ {name: ‘Aruna’, age:21}, {name:’Calvin’, age:21}, {name:’Rohit’, age: 20}, {name:’Shobit’, age: 19} ]
Note that the objects are already sorted by name in the alphabetical order.
Now lets sort the objects in ascending order based on age instead.
info.sort(function(a,b){
return a.age — b.age }
Output:
[
{ name: ‘Shobit’, age: 19 },
{ name: ‘Rohit’, age: 20 },
{ name: ‘Aruna’, age: 21 },
{ name: ‘Calvin’, age: 21 }
]
Notice that the names that have the same age will remain in the same order as before calling the sort method. Here Arunava still comes before Calvin after sorting.
Therefore the sort( ) method is stable.
Activity 1
Consider an array of objects
const students = [
{ name: ‘A’, course1: 50 , course2: 40},
{ name: ‘B’, course1: 70 , course2: 30},
{ name: ‘C’, course1: 20 , course2: 44}
]
Sort the students in ascending order of the total marks scored in the courses.
Solution
Total marks of each student is nothing but course1 + course2.
To sort the students in ascending of their total marks,
students.sort(function(a, b){
return (a.course1+ a.course2) — (b.course1 + b.course2)
})
Output
[
{ name: ‘C’, course1: 20, course2: 44 },
{ name: ‘A’, course1: 50, course2: 40 },
{ name: ‘B’, course1: 70, course2: 30 }
]
Activity 2
Say you have an array of objects
const movies =
[
{ name: ‘Titanic’, imdb: 9.5, rottenTomatoes: 88},
{ name: ‘Avatar’, imdb: 9.5, rottenTomatoes: 73},
{ name: ‘Batman’, imdb: 9.0, rottenTomatoes: 85},
{ name: ‘Rango’, imdb: 7.0, rottenTomatoes:100},
{ name:’Interstellar’, imdb:9.0, rottenTomatoes:76}
]
Sort the movie objects based on the imdb rating in ascending order. If the imdb rating is the same for any two movies, sort those movies by their rotten tomatoes rating.
Solution
movies.sort(function(a,b){
return a.imdb — b.imdb || a.rottenTomatoes — b.rottenTomatoes
})
console.log(movies)
Output
[
{ name: ‘Rango’, imdb: 7, rottenTomatoes: 100 },
{ name: ‘Interstellar’, imdb: 9, rottenTomatoes: 76 },
{ name: ‘Batman’, imdb: 9, rottenTomatoes: 85 },
{ name: ‘Avatar’, imdb: 9.5, rottenTomatoes: 73 },
{ name: ‘Titanic’, imdb: 9.5, rottenTomatoes: 88 }
]
Explanation
If a.imdb-b.imdb expression evaluates to 0 (i.e if the imdb ratings are the same), it will proceed with evaluating || expression -and return the result of a.rottenTomatoes-b.rottenTomatoes.
Wrap Up
The comparator function in sort thus proves to be very versatile for various kinds of applications. When sort( ) is used along with other higher order functions of javascript, it becomes an even more powerful tool. Further reading will involve how to reduce the complexity of sort( ) with the help of other higher order functions such as map( ) in javascript.