The Talent500 Blog
The culprit behind the sort() method in JavaScript 1

The culprit behind the sort() method in JavaScript

Do you know why the sort() method behaves like [20, 1000, 500, 30000, 2, 0, 500].sort( ) = [0, 1000, 2, 20, 30000, 500, 500] ?

So don’t worry, in this article we are going to see what the main logic behind the scene is.

An overview of the sort() method:

  • The sort() method allows us to sort the elements of the array. It changes the positions of the elements in the original array. In other words, the sort() method mutates the original array.
  • By default, it sorts the elements of the array in ascending order, which means the smallest value will be the first one, and the largest value will be the last one.
  • The sort() method typecasts (Converts one type to another type) the elements into strings and compares the strings to determine the order of the elements.

Example 1:

let char = [“k”, “i”, “a”, “p”, “m”, “a”];

console.log(char.sort());

// [ ‘a’, ‘a’, ‘i’, ‘k’, ‘m’, ‘p’ ]

let char = [‘K’, ‘I’, ‘A’, ‘P’, ‘M’, ‘A’];

console.log(char.sort());

//[ ‘A’, ‘A’, ‘I’, ‘K’, ‘M’, ‘P’ ]

Suppose we want to sort an array that contains the small letters and capital letters of the alphabet. Then it will give the output as expected.

The output will be: [ ‘a’, ‘a’, ‘i’, ‘k’, ‘m’, ‘p’ ] and [ ‘A’, ‘A’, ‘I’, ‘K’, ‘M’, ‘P’ ], right?

Example 2:

Now let’s make this example complex. Suppose we want to sort mixed letters using the sort() method. Then it will not give the expected output.

let letters = [‘U’, ‘E’, ‘i’, ‘o’, ‘a’];

let sortMixLetters = letters.sort();

console.log(sortMixLetters);

// [ ‘E’, ‘U’, ‘a’, ‘i’, ‘o’ ]

The output of the above code snippet will be [ ‘E’, ‘U’, ‘a’, ‘i’, ‘o’ ] which is not expected, but who is the culprit here?

We will see the actual logic behind the scene later in this article, but before we do, we are going to see some more examples with the number data type.

Example 3:

Now we want to sort an array that contains the Number data type using the sort() method. But it also does not return the expected result. Who is the culprit here too?

let numbers = [20, 1000, 500, 30000, 2, 0, 500];

console.log(numbers.sort());

//[0, 1000, 2, 20, 30000, 500, 500]

Let’s find out the culprit😇

The culprit of Example 2:

let letters = [‘U’, ‘E’, ‘i’, ‘o’, ‘a’];

let sortMixLetters = letters.sort();

console.log(sortMixLetters);

// [ ‘E’, ‘U’, ‘a’, ‘i’, ‘o’ ]

Actually, it is just working perfectly. But the actual culprit here is Unicode(ASCII) values.

Yes, the sort() method sorts the elements of the array on the basis of Unicode values but not string values. You can also find the Unicode value using the charCodeAt( ) string method.

let letters = [‘U’, ‘E’, ‘i’, ‘o’, ‘a’];

letters.forEach(item => {

  console.log(item, ‘=>’, item.charCodeAt(0));

});

/*

U => 85

E => 69

i => 105

o => 111

a => 97

*/

As I mentioned before, the sort() method sorts the elements of the array in ascending order by default, so the smallest Unicode value is sorted first, then the largest Unicode value will be sorted.

That means, the order of the elements of the sorted array will be 69(E), 85(U), 97(a), 105(i), and 111(o)

That’s why it returns the output like [ ‘E’, ‘U’, ‘a’, ‘i’, ‘o’ ], don’t worry we will fix this problem later in this article.

The culprit of Example 3:

Now let’s find out the culprit with the Number type of array elements.

In this case, the JavaScript engine converts the Number types of elements into String types and then sorts them on the basis of Unicode values.

let numbers = [20, 1000, 500, 30000, 2, 0, 500];

console.log(numbers.sort());

//[0, 1000, 2, 20, 30000, 500, 500]

Again, we are going to convert all Number elements of the array into Unicode values using the charCodeAt() method.

However, we must manually convert all array elements to Strings type before using the charCodeAt() method on top of that.

let numbers = [20, 1000, 500, 30000, 2, 0, 500];

numbers.forEach(item => {

          console.log(item, “=>”, String(item).charCodeAt(0));

});

/*

20    => 50

1000  => 49

500   => 53

30000 => 51

2     => 50

0     => 48

500   => 53

*/

So, we can clearly see that the smallest Unicode value is 48(0), that’s why it will be sorted first then 49(1000), 50(2), 50(20), and so on.

Congratulations, we have found the actual culprit behind the scenes of the sort() method. But what are the solutions?

Solution: Compare Function

Yes, to resolve this problem, we need to pass a compareFunction to the sort() method. The sort() method accepts an optional argument, which is a compareFunction that compares two elements of the array.

If we omit the compareFunction, the sort() method sorts the elements on the basis of Unicode values. But if we pass a compareFunction to the sort() method, then it sorts elements on the basis of the return value of the compareFunction.

Syntax of compareFunction:

The compareFunction accepts two arguments that are two continuous elements of the array. The a and b parameters of the compareFunction are two continuous elements of the array.

function compareFunction(a, b){

  //Lines of code

}

Solution of Example 2:

let letters = [‘U’, ‘E’, ‘i’, ‘o’, ‘a’];

let sortMixLetters = letters.sort();

console.log(sortMixLetters);

// [ ‘E’, ‘U’, ‘a’, ‘i’, ‘o’ ]

Now we are going to fix the problem with compareFunction. These are the following steps:

  1. We need to convert all letters to the same case.
  2. Then we have to check certain conditions.

Conditions:

  • If a’s charCode > b’s charCode, then return any positive value that means we need to change the order of the letters in the array.
  • If charCode of a < charCode of b, returns any negative value, do not need to change the order of the letters in the array.
  • If both charCodes are the same, then return 0 (nothing).

Still having trouble understanding this? I promise you will understand after the next example. 🙂

let letters = [‘U’, ‘E’, ‘i’, ‘o’, ‘a’];

let sorted = letters.sort(compareLetters);

console.log(sorted); //[a, E, i, o, U]

function compareLetters(a, b) {

  //step 1

  let charCode1 = a.toLowerCase();

  let charCode2 = b.toLowerCase();

  //step 2

  //suppose U = 85 > E = 69 (SWAP)

  if (charCode1 > charCode2) return 1;

  //suppose i = 105 > o = 111 (NOT SWAP)

  if (charCode1 < charCode2) return -1;

  //suppose i = 105 === i = 105 (NOTHING)

  return 0;

}

Solution of Example 3:

let numbers = [20, 1000, 500, 30000, 2, 0, 500];

console.log(numbers.sort());

//[0, 1000, 2, 20, 30000, 500, 500]

To sort the Number type of elements in the array, we need to pass another compareFunction to the sort() method.

Parameters of the compareFunction:

  • a – First item of the array.
  • b – Second item of the array.

Now we need to check the above condition again:

  • If a > b = true, then we need to swap the order of the array elements, that’s why we have to pass any positive value to the compareFunction.
  • If b > a = true, then we don’t need to swap the order of the array elements, which means we have to pass any negative value to the compareFunction.
  • If a = b, both values will be the same. We don’t need to do anything.

That’s it, ladies and gentlemen. See the code below.

let numbers = [20, 1000, 500, 30000, 2, 0, 500];

console.log(numbers.sort(compareFunction));

// [0, 2, 20, 500, 500, 1000, 30000]

function compareFunction(a, b) {

          // Need to swap

          // 1000 > 500 = it’s not perfect (SWAP)

          if (a > b) return 99;

          // Not need to swap

          // 500 > 1000 = it’s perfect (NOT SWAP)

          if (b > a) return -69;

          //Nothing

          //500 = 500 (Everything is perfect)

          return 0;

}

Refactor the code

But we can also make it easier than the above code. Let’s refactor the code:

Suppose, a = 20 , b = 100

If I subtract both of them(a – b), it returns a negative number, right?

Now, a = 100 , b = 20

Again, if I subtract both of them(a – b), it returns a positive number, right?

And, a = 50, b = 50

If I subtract both of them(a – b), it returns 0, right?

That means, can I replace the above conditions with (a – b)?

So, yes we can replace the above conditions with (a – b)?  see the code below.

let numbers = [20, 1000, 500, 30000, 2, 0, 500];

console.log(numbers.sort(compareFunction));

// [0, 2, 20, 500, 500, 1000, 30000]

function compareFunction(a, b) {

  return a – b;

  // 20 -1000 = Negative value(Not SWAP)

  // 1000 – 500 = Positive value(SWAP)

  // 500 – 500 = 0 (Nothing)

}

And last but not least, if you want to sort an array in descending order, then you only have to change the order of the return value with (b – a).

Conclusion

The sort() method sorts the elements of the array on the basis of Unicode values. In order to fix that problem, we need to pass a compareFunction to the sort() method as a callback function. The callback function accepts two parameters, which are the first and second elements of the array.

 

 

10+
Ajay Yadav

Ajay Yadav

I am a frontend developer and am eager to deep dive into the technologies through my content.

Add comment