Table Of Contents
- Hello Reader
- JavaScript's sort() function
- Sorting Primitives
- Sorting an Array of Objects
- Final Thoughts
Hello Reader ๐๐ฝ
I was tired of searching on Google when I was unsure of how to sort whatever data I'm using in JavaScript, so I decided to write it all in one place.
Today, we are going to learn about sorting in JavaScript. Starting with the history and algorithm used for .sort()
. Then learning how to sort primitives and objects. Let's jump in!
JavaScript's sort() function ๐
The .sort()
function sorts an array in-place (meaning no copy is made) and returns the sorted array. We can't modify the algorithm used by .sort()
, but we can modify how it compares array elements by passing a compare function
.
// Native, without a compare function
sort()
// With an arrow pointing compare function
sort((a, b) => {
...
})
// Passing a compare function
sort(compareFn)
Implementation History
In Chrome, back in the ye-old days, the sorting algorithm wasn't as good as today. One of its previous implementations included insertion sort O(n2) ๐คข.
Today we are in a better state with a modification of Merge Sort named Tim Sort O(n log n) ๐. Initially created by Time Peters as an adaptive stable Merge Sort variant.
A stable sorting algorithm means if two values of the same value sit next to each other, they maintain the same order after sorting. You'd be surprised how many algorithms depend on this.
Sorting Primitives
Let's go over how to sort primitives with .sort()
.
Sorting an Array of Strings
The sort()
function works how you'd expect for strings.
const names = ["Darui", "Bee", "Naruto", "Ada", "Sasuke", "Baki", "A"];
console.log(names.sort());
// Output: ["A", "Ada", "Baki", "Bee", "Darui", "Naruto", "Sasuke"]
JavaScript by default sorts in Lexicographical order. Lexicographical order means sorted alphabetically sort of like a dictionary. If two strings are equal, then the shortest one is put first.
// Lexicographical order
const str = ["aab", "ba", "aac", "bab", "aaa", "Aab", "aaaa"];
// Results
"Aab" // Uppercase letters take precedence
"aa|a"
"aa|aa" // Is equal to "aaa" but is longer
"aa|b" // The 3rd char 'b' comes the third char 'a' in the strings above.
"aa|c" // The last char 'c' comes after 'b'
"ba" // The first char 'b' comes after 'a' in the above strings
"bab"
Sorting an Array of Numbers ๐งฎ
Using .sort()
on numbers is a bit tricky. It DOES NOT work natively.
const scores = [9, 80, 19, 4, 20, 53];
// Wrong โ
console.log(scores.sort());
// Wrong order ๐๐ฝ
// Output: [19, 20, 4, 53, 80, 9]
By default, JavaScript sorts in Lexicographical order. Great for strings but terrible for numbers. We have to pass a compare function
.
Compare Function
The compare function
returns an integer which .sort()
uses to determine the order when comparing elements.
function compareNumbers(a, b) {
if (a < b) {
return -1; // sort a before b
} else if (a > b) {
return 1; // sort a after b
}
return 0; // keep a and b in the same order
}
When two elements are passed to the compare function
, if it returns less than 0, a
is put first. If the result is greater than 0, b
is put first. If the result is equal to 0, keep a
and b
in the same order. Ex. a(3) - b(2)
is 1 which puts b(2)
in front of a(3)
.
To properly sort numbers, we introduce a compare function
to sort numbers in ascending order.
let scores = [9, 80, 19, 4, 20, 53];
// Sort in ascending order โ
scores.sort((a, b) => {
return a - b;
});
console.log(scores);
// Output: [4, 9, 19, 20, 53, 80]
Descending Order
Descending order is an easy 1 line change. Instead of using a - b
, use b - a
to reverse the order. Take our a(3) - b(2)
example from earlier. If we change it to b(2) - a(3)
, we get -1. This instead puts a(3)
in front of b(2)
.
let scores = [9, 80, 19, 4, 20, 53];
// Sort in descending order
scores.sort((a, b) => {
return b - a;
});
console.log(scores);
// Output: [80, 53, 20, 19, 9, 4]
Sorting an Array of Objects ๐๏ธ
In JavaScript, an object is a variable with a collection of properties in key:value
pairs.
// Array of objects with two properties, 'name' and 'titansDefeated'.
const characters = [{
name: 'eren',
titansDefeated: 1
},
{
name: 'mikasa',
titansDefeated: 20
},
{
name: 'levi',
titansDefeated: 90
},
{
name: 'armin',
titansDefeated: 10
},
];
Since objects have multiple properties, we pass a compare function
to sort by the property we want.
Sorting by the amount of titansDefeated
in ascending order.
const characters = [{
name: 'eren',
titansDefeated: 1
},
{
name: 'mikasa',
titansDefeated: 20
},
{
name: 'levi',
titansDefeated: 90
},
{
name: 'armin',
titansDefeated: 10
},
];
characters.sort((a, b) => {
return a.titansDefeated - b.titansDefeated;
});
console.log(characters);
// Output: [{
// name: "eren",
// titansDefeated: 1
// }, {
// name: "armin",
// titansDefeated: 10
// }, {
// name: "mikasa",
// titansDefeated: 20
// }, {
// name: "levi",
// titansDefeated: 90
// }]
Sorting by the amount of titansDefeated
in descending order.
const characters = [{
name: 'eren',
titansDefeated: 1
},
{
name: 'mikasa',
titansDefeated: 20
},
{
name: 'levi',
titansDefeated: 90
},
{
name: 'armin',
titansDefeated: 10
},
];
characters.sort((a, b) => {
return b.titansDefeated - a.titansDefeated;
});
console.log(characters);
// Output: [{
// name: "levi",
// titansDefeated: 90
// }, {
// name: "mikasa",
// titansDefeated: 20
// }, {
// name: "armin",
// titansDefeated: 10
// }, {
// name: "eren",
// titansDefeated: 1
// }]
Sorting by names
in lexicographical order.
const characters = [{
name: 'eren',
titansDefeated: 1
},
{
name: 'mikasa',
titansDefeated: 20
},
{
name: 'levi',
titansDefeated: 90
},
{
name: 'armin',
titansDefeated: 10
},
];
// Sort names in case-insensitive
// lexicographical order
characters.sort((a, b) => {
// Convert to uppercase so we don't have
// to worry about case differences.
const nameA = a.name.toUpperCase();
const nameB = b.name.toUpperCase();
if (nameA < nameB) {
return -1;
}
if (nameA > nameB) {
return 1;
}
// names must be equal
return 0;
});
console.log(characters);
// Output:[{
// name: "armin",
// titansDefeated: 10
// }, {
// name: "eren",
// titansDefeated: 1
// }, {
// name: "levi",
// titansDefeated: 90
// }, {
// name: "mikasa",
// titansDefeated: 20
// }]
Final Thoughts ๐ญ
Here's everything you need for sorting in JavaScript all in one place. In Chrome, .sort()
is implemented using the Tim Sort algorithm. By default .sort()
sorts in lexicographical order, great for strings but not so much for anything else. We pass a compare function
for numbers and objects to define the sorting order.
I'm Gregory Gaines, a goofy software engineer @Google who's trying to write good articles. If you want more content, follow me on Twitter at @GregoryAGaines.
Now go create something great! If you have any questions, hit me up on Twitter (@GregoryAGaines); we can talk about it.
Thanks for reading!
Top comments (3)
If two strings are equal, none of them is shorter ๐
If one of them starts with the other (e.g. "longer" and "long"), it's put after.
Nice comment.
I meant in the context of being lexicographically equal, I should have been clearer.
Why not just use localeCompare ?