Sort method in JavaScript
08 May 2019Table of Contents
- Unexpected results
- How JS Sort Method Works
- compareFunction Parameter
- Compared with Python Sort Method
Unexpected results
Fortunately, JavaScript offers sort method for arrays. You can search it from MDN in the name of “Array.prototype.sort()”. Despite it’s convienence, it frequently yields unexpected results compared to Python’s sort method.
First, let’s just compare sorted results from both Python and JS.
# Python
a = [10, 3, 7, 99, 2, 1]
a.sort()
# l = [1, 2, 3, 7, 10, 99]
Easy to understand. Loud and Clear. But, how about in JS?
// JavaScript
a = [10, 3, 7, 99, 2, 1]
a.sort()
// a = [ 1, 10, 2, 3, 7, 99 ]
What? It aint got sorted, or is it? Let’s see some more ex.
# Python
a = [1, 'a', '10', 99, 3, 7, 10]
a.sort()
# TypeError: '<' not supported between instances of 'str' and 'int'
// JavaScript
a = [1, 'a', '10', 99, 3, 7, 10]
a.sort()
// a = [ 1, '10', 10, 3, 7, 99, 'a' ]
If you try to sort list with both str elements and int elements, Python throws an TypeError, yet JavaScript doesn’t.
For the last, look at this:
// JavaScript
a = [1, 9, 8, 0, 4]
a.sort()
// a = [ 0, 1, 4, 8, 9 ]
The array has been sorted in ascending order as expected.
We are engineers so we need to know how the sorting method actually works in JS. Let’s see through it.
How JS Sort Method Works
JavaScript sort method compares UTF-16 codes of its elements that are converted into string.
The default sort order is built upon converting the elements into strings, then comparing their sequences of UTF-16 code units values.
[Source: Array.prototype.sort(), MDN]
If [‘10’, 10, 1] is the array to sort, JavaScript default sort method will yield [ 1, ‘10’, 10 ].
‘10’ is regarded equal to number type 10, since JavaScript treats all elements just like a string.
So, it is not surprising even if we got [‘10’, 2] from [2, ‘10’] sorted with Array.prototype.sort().
Then, if we want to sort number elements in ascending/descending order, how could we do?
Luckily, JavaScript sort() takes an compareFunction.
compareFunction Parameter
There are few ground rules to know about the compareFunction parameter that Array.prototype.sort() takes.
- f compareFunction(a, b) is less than 0, sort a to an index lower than b (i.e. a comes first).
- If compareFunction(a, b) returns 0, leave a and b unchanged with respect to each other, but sorted with respect to all different elements. Note: the ECMAscript standard does not guarantee this behavior, thus, not all browsers (e.g. Mozilla versions dating back to at least 2003) respect this.
- If compareFunction(a, b) is greater than 0, sort b to an index lower than a (i.e. b comes first).
- compareFunction(a, b) must always return the same value when given a specific pair of elements a and b as its two arguments. If inconsistent results are returned, then the sort order is undefined.
[Source: MDN]
Therefore, sorting and array with number elements in ascending order could be:
a = [1, 10, 3, 7, 8, 1, 8, 10]
a.sort((a, b) => a - b)
// a = [ 1, 1, 3, 7, 8, 8, 10, 10 ]
If a-b > 0, sort method will treat b to get lower index. Else if a-b < 0, it will treat a to get lower index. Else if a -b === 0, there could be no change at all.
The good thing is, you can manually modify the way sort method works.
// Let's imitate Array.prototype.reverse()
a = [1, 2, 3, 4, 5]
a.sort(x=> 1)
// a = [5, 4, 3, 2, 1]
// Sort odd numbers, even numbers must be on their places
function sortArray(array) {
const odds = array.filter(e => e % 2 === 1).sort((e1, e2) => e1 - e2);
return array.map(e => (e % 2 ? odds.shift() : e));
}
You can manipulate as much as your imagination and creativity allows.
Compared with Python Sort Method
Python has built in sorting functions like sort() and sorted().
list.sort() sorts the list in ascending order. If strings are given in the list, it sorts by Unicode code points.
First, sort() is a method of list class. Compared to sorted() that takes any iterables as first parameters, sort() takes only lists.
list.sort() takes two parameters, key and boolean value for reverse.
a = ['A', 'b', 'C', 'D', 'e', 'f']
a.sort() # ['A', 'C', 'D', 'b', 'e', 'f']
a = ['A', 'b', 'C', 'D', 'e', 'f']
a.sort(key=str.upper) # ['A', 'b', 'C', 'D', 'e', 'f']
As you may find out, the value of the key parameter should be a function that takes a single argument and returns a key to use for sorting purposes.
We can also assign order by adding reverse options.
a = [1, 2, 5, 4, 3]
a.sort(reverse=True) # [5, 4, 3, 2, 1]
# As you may noticed, both key and reverse params could be omitted
Python distinguishes elements of the list to be sorted. It doesn’t compare string to number types(int, float).
You cannot sort [1, ‘a’, 3, ‘10’] since ‘<’ is not supported between int and str.
To sum up:
JavaScript
- treats elements as a string.
- Sort in ascending order of UTF-16 codes of every elements by default.
- A callback function that returns number can be given to set rules.
Python
- treats number and string differently.
- String elements are compared by UTF-8(usually default) codes.
- Sort in ascending order by default.