DEV Community

Felix Guerin
Felix Guerin

Posted on

Understanding sort()

The first time I had to use sort() in a project, I had some difficulty wrapping my head around how it works. I hope this post will help you better understand it.

sort() is a Javascript array method used to (you guessed it) sort an array.

Ok, so far so good.

Its use can be pretty straightforward, as in the example below, where we sort an array of strings by alphabetical order.

const myStringsArray = ['George', 'Matt', 'Sandy', 'Laurent', 'Felix', 'Phil'];

myStringsArray.sort(); // [ "Felix", "George", "Laurent", "Matt", "Phil", "Sandy" ]

Easy! Now let's do the same for numbers.

const myNumbersArray = [2, 7, 4, 13, 20, 5, 15, 18, 9];

myNumbersArray.sort(); // [ 13, 15, 18, 2, 20, 4, 5, 7, 9 ]

Hey that's not right! What is going on here?

Well, by default the sort() method sorts any values passed to it as strings. In this case, the numbers are sorted as "13", "15", "18", "2", etc. It now makes sense, because in an alphabetical order, "15" comes after "13", and "2" comes after "18".

The Compare Function

If we want to use sort() with actual numbers, we need to use the built-in compare function. This callback function defines an alternative sorting order. It takes two arguments, two values that are being compared against each other. The function then returns either a positive value, a negative value or zero.

If we take again our numbers array, we can pass the values of the array in our compare function to sort them in ascending order.

const myNumbersArray = [2, 7, 4, 13, 20, 5, 15, 18, 9];

myNumbersArray.sort((value1, value2) => {
    return value1 - value2;
}); // [ 2, 4, 5, 7, 9, 13, 15, 18, 20 ]

So how does that work?

The sort() method iterates over the array, every time passing 2 values next to each other to the compare function. The compare function then evaluates the difference between the first value and the second. This is what will determine whether the function returns a positive, negative or neutral value.

If the return value is positive, it means that the first value is greater than the second. For example, if you compare 7 and 4, you get 3. Therefore, the first value goes after the second one in our ascending order.

If the return value is negative, it means that the first value is less than the second. For example, if you compare 2 and 7, you get -5. Therefore, the first value goes before the second one in our ascending order.

A neutral value, or zero, indicates that the two values are equal, so the order does not need to change.

You can actually do any operation you want inside the compare function, as long as you return a value.

If we want to sort our numbers array in descending order, we can do the following:

const myNumbersArray = [2, 7, 4, 13, 20, 5, 15, 18, 9];

myNumbersArray.sort((value1, value2) => {
    return value1 + value2;
}); // [ 20, 18, 15, 13, 9, 7, 5, 4, 2 ]

Sorting Objects

Sorting an array of objects is not really more complicated. You can sort them by any property you'd like, but you have to be mindful of the type of value associated with that property.

If we want to sort the objects by a number property, we do it exactly like we did before. We just need to access the property with dot notation.

const myObjectsArray= [
    { item: "chair", price: 400 },
    { item: "bed", price: 1200 },
    { item: "table", price: 800 },
    { item: "sofa", price: 1000 },
    { item: "desk", price: 500 }
];

myObjectsArray.sort((value1, value2) => {
    return value1.price - value2.price;
}); // [
        // { item: "chair", price: 400 },
        // { item: "desk", price: 500 },
        // { item: "table", price: 800 },
        // { item: "sofa", price: 1000 },
        // { item: "bed", price: 1200 }
    // ];

Now for a string (or a date value), we have to add some more steps. Since we can't directly sort the strings found in an object (because we are sorting the objects themselves), we have to access the values inside our compare function. Now, since comparing two strings together won't return a positive or negative value, we also need to return it ourselves.

const myObjectsArray= [
    { item: "chair", price: 400 },
    { item: "bed", price: 1200 },
    { item: "table", price: 800 },
    { item: "sofa", price: 1000 },
    { item: "desk", price: 500 }
];

myObjectsArray.sort((value1, value2) => {
    if (value1.item === value2.item) {
        return 0;
    } 
    return value1.item > value2.item ? 1 : -1;
}); // [
        // { item: "bed", price: 1200 }
        // { item: "chair", price: 400 }
        // { item: "desk", price: 500 }
        // { item: "sofa", price: 1000 }
        // { item: "table", price: 800 }
    // ];

Here, if the first string is "greater" (comes after in alphabetical order)
than the second one, we return a positive value so that value1 is put after value2. Just like with numbers, if the first value is greater than the second, it is put after. If it is less, it is put before. We return 0 when both values are equal to preserve the original order. Otherwise, while both values would be next to each other in the sorted array, their order might change on every function call.

So remember, whenever the values of the objects you want to sort aren't numbers, you need to return a positive or negative value yourself.

Conclusion

And there you have it! sort() is a really neat Javascript native function, and you can do much more complex things with it, but this post covered the basics. Happy sorting!

Discussion (5)

Collapse
hi_iam_chris profile image
Kristijan Pajtasev

Nice post.

If you don't mind i would just add for string example, it is worth also handling equal case where in case of equal values you return 0 in order to keep it stable sort.

When we have array of strings it doesn't make much difference, but in case of objects sorted based on some property, let's say name, it is worth keeping same order of equal values.

Collapse
felix profile image
Felix Guerin Author

Hey thanks for reading!

I thought about return 0 in case of equal value but from what I've seen, sort() places equal values next to each other in the sorted array even without it. I figured this could allow me to keep my code even shorter.

Have you seen any case where this could lead to errors?

Collapse
hi_iam_chris profile image
Kristijan Pajtasev

Not actually error but only if you care about keeping original order.

For example:
[{fName: "john", lName: "doe"}, {fName: "john", lName: "smith"}]

When stable sort (returning 0 for equal) on name it would always return
[{fName: "john", lName: "doe"}, {fName: "john", lName: "smith"}]

But when unstable (returning 1 when greater, -1 every other time or opposite) once will return above next time might opposite order
[{fName: "john", lName: "smith"}, {fName: "john", lName: "doe"}]

So it more depends on requirements

Thread Thread
felix profile image
Felix Guerin Author

I hadn't thought of that! Indeed, I just tested it several times and it IS unstable if you don't return 0 for equal values. I edited the post to include it.

Thank you so much for this!

Thread Thread
hi_iam_chris profile image
Kristijan Pajtasev

NP it is really good post regardless :)