DEV Community

Cover image for The Only JavaScript Sorting Guide You'll Ever Need
Gregory Gaines
Gregory Gaines

Posted on • Updated on • Originally published at gregorygaines.com

The Only JavaScript Sorting Guide You'll Ever Need

Table Of Contents


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)
Enter fullscreen mode Exit fullscreen mode

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());
Enter fullscreen mode Exit fullscreen mode
// Output: ["A", "Ada", "Baki", "Bee", "Darui", "Naruto", "Sasuke"]
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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());
Enter fullscreen mode Exit fullscreen mode
// Wrong order ๐Ÿ‘Ž๐Ÿฝ
// Output: [19, 20, 4, 53, 80, 9]
Enter fullscreen mode Exit fullscreen mode

By default, JavaScript sorts in Lexicographical order. Great for strings but terrible for numbers. We have to pass a compare function.


Who gets sorted first?


Compare Function


Compare function interpretation


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
}
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode
// Output: [4, 9, 19, 20, 53, 80]
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode
// Output: [80, 53, 20, 19, 9, 4]
Enter fullscreen mode Exit fullscreen mode

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
  },
];
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode
// Output: [{
//  name: "eren",
//  titansDefeated: 1
// }, {
//  name: "armin",
//  titansDefeated: 10
// }, {
//  name: "mikasa",
//  titansDefeated: 20
// }, {
//  name: "levi",
//  titansDefeated: 90
// }]
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode
// Output: [{
//  name: "levi",
//  titansDefeated: 90
// }, {
//  name: "mikasa",
//  titansDefeated: 20
// }, {
//  name: "armin",
//  titansDefeated: 10
// }, {
//  name: "eren",
//  titansDefeated: 1
// }]
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode
// Output:[{
//  name: "armin",
//  titansDefeated: 10
// }, {
//  name: "eren",
//  titansDefeated: 1
// }, {
//  name: "levi",
//  titansDefeated: 90
// }, {
//  name: "mikasa",
//  titansDefeated: 20
// }]
Enter fullscreen mode Exit fullscreen mode


Levi said "sort faster"


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)

Collapse
 
maxart2501 profile image
Massimo Artizzu

If two strings are equal, then the shortest one is put first.

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.

Collapse
 
gregorygaines profile image
Gregory Gaines • Edited

Nice comment.

I meant in the context of being lexicographically equal, I should have been clearer.

Collapse
 
sesay profile image
sesay

Why not just use localeCompare ?