Why isn't .sort() working as expected?

Question

Why isn’t .sort() working as expected?

Answer

When we use .sort(), if we do not specify a function that defines the sort order, each element of the array will be converted to a string then sorted in ascending order based on each character’s Unicode point value.
For example:

const myArr = [400, 100000, 560];

console.log(myArr.sort())//logs [ 100000, 400, 560 ] to the console because each number is converted to a string then sorted in ascending order based on Unicode code point value

To solve this issue we’ll want to pass .sort() a function that defines the sort order:

const myArr = [400, 100000, 560];

const checkNumbers = (num1, num2) => num1 - num2;

console.log(myArr.sort(checkNumbers));//logs [ 400, 560, 100000 ] to the console

Hi, I’m interested in what’s happening in this checkNumbers function, specifically the num1 - num2 part. What is the minus sign doing in this code? Please could you describe the process of myArr.sort(checkNumbers)? Thank you.

7 Likes

I had the same question. Check out the MDN reference on the .sort() method. I still don’t understand the concept completely, but it seems like its just part of the method. You give it two variables like a and b, or x and y, it subtracts them to determine which one is larger. It does one thing if the result of the subtraction is positive, and the opposite if the result is negative. Seems like you always just pick two variables and subtract the 2nd one from the 1st one. It will iterate this process through each unit in the array

3 Likes

Hey if you’re wondering what’s happening to the “minus” and what’s running behind the code, check this video out![.sort() tutorial] (https://www.youtube.com/watch?v=MWD-iKzR2c8)

23 Likes

The example uses < instead of -. (https://www.codecademy.com/paths/web-development/tracks/web-dev-js-arrays-loops-objects/modules/web-dev-intermediate-javascript-practice/lessons/intermediate-javascript-coding-challenge/exercises/sort-years)

Maybe this will help someone:

Compare function takes two parameters, which are named “a” and “b”.

const compare = (a, b) => {}

If the function’s returned value is a negative number (ex. -1), then the first argument (in this case “a”) will be sorted before the “b” argument (ie. at an index lower then “b”).

If returned value is a positive number (ex. 1), then the first argument (“a”) will be sorted after the “b” argument (ie. at an index higher then “b”).

If function block contains statement:

return a - b;

and for example, the value of “a” is 100 and the value of “b” is 200, then a - b expression returns a value of -100, which is a negative number and the “a” argument will be sorted before the “b” argument.

If you reverse the values, “a” is 200 and “b” is 100, then a - b expression returns 100, which is a positive number and the “a” argument will be sorted after the “b” argument.

The sorting outcomes of both examples may be different, but the smaller number was always sorted before the bigger number. So that means an expression a - b will always put the smaller number before the bigger number (array will be sorted in ascending order).

Statement :

return b - a 

will always sort the array in descending order. If value of “a” is 100 and value of “b” is 200, result is 100 and “a” is sorted after “b” (ie. in descending order) and vice versa.

You could achieve ascending sorting with either of the if statements:

if (a < b) {
  return -1;
}
// or
if (a > b) {
  return 1;
}

Both examples will sort the smaller number before the bigger number.

26 Likes

One thing to note here is what happens when a - b = 0.
When using numbers we don’t care as we cannot differentiate between two numbers that are the same, but in some cases we might care. Say we had objects that had a numerical property that we was going to compare by, if a - b was equal what would happen with the ordering of the two objects? An example of such code

// objArray made previously with objects that have a property of value that is numeric.

objArray.sort((objA, objB) => objA.value - objB.value);

The answer is it depends on the version of JavaScript you are using. In the 2019 specification it started to state that sort should be stable. Stable here means that where two items are evaluated to be equal they will maintain their original order. Before this sort was not guaranteed to be stable, so you could not assume that the original ordering would be maintained.

8 Likes

I did not know that. Thanks for sharing.

So it means that in the latest version of JavaScript, if comparing numerical object properties and objA.value - objB.value = 0, the original order of objects will be maintained? And in the older version, the order would we random each time the array was sorted? Is this correct?

Yes, if an interpreter supports the latest version of JS the original order would be maintained. The older version wouldn’t be random, rather the behaviour would change depending what is running the is. For example, Chrome might be stable but Firefox might not be (I think it is actually stable in all the major browsers now in realty). It could even change under certain circumstances for the same environment, such as large arrays using a different algorithm to small arrays, one algorithm might be stable and the other not.

One thing to note though is it will be a good few years before the 2019 spec is the standard, Chrome hasn’t fully implemented the 2017 spec yet unless I’m mistaken. So unless you know what your code will be running on for the time being assume it isn’t stable.

3 Likes

Thank you for explaining this in detail. I haven’t yet gotten to algorithms but I will keep it in mind going forward.

When I checked the Hint it showed the compare function just using the relational operators:

Not sure how this works… If its true ‘year2’ goes first and if its false ‘year1’ goes first?

1 Like

I think that the example in hint has a typo. Instead of comparing parameters the expression should read year 1 - year 2 to get ascending sorting functionality.

If you just compare values like the hint shows, the array does not get modified/sorted.

I went a different route when sorting this part of the course.

const sortYears = yearInput => yearInput.sort().reverse();

3 Likes

It really helped me. Thnaks!!

Really helpful video, thanks for sharing!

Newbies, must not watch this. Or they will lose their motivation. But higly recommended video. :joy:

How come when I use this code:

const sortYears = arr => arr.sort((yearl, year2) => year2 - year1);

I get an error. But when I replace year1 and year2 with x and y, the code works?:

const sortYears = arr => arr.sort((x, y) => y - x);

looks like you just have a typo in there - yearl instead of year1

2 Likes

This is a great reference. Thank you for sharing. Helped me out on this example!

Hello,

I think your code only works with these specific years. If you add 999 to the array “years”, your code returns the wrong order. (Same for any year with less than 4 digits.)

1 Like