Start learning free

LESSON 263 OF 671 · DESTRUCTURING, SORTING & BUILT-INS

Custom Sorting in JavaScript: sort with a Compare Function

Lesson Read the full explanation

TL ; DR:

To sort by your own rule, give sort a compare function. It gets two items, a and b. A negative result puts a first.


let nums = [25, 13, 5, 41, 33];

nums.sort((a, b) => {
    if (a % 10 !== b % 10) {
        return a % 10 - b % 10;
    }

    return a - b;
});
// [41, 13, 33, 5, 25]

let scores = [70, 95, 82];

scores.sort((a, b) => b - a);
// [95, 82, 70]


Full lesson:

You met sort() in the Shopping Cart project. It sorted text from A to Z. Sometimes you need another order. The shortest word may have to come first, or the highest score.

Watch out with numbers. A plain sort() compares them as text. So [10, 9, 1].sort() gives [1, 10, 9].

To sort by your own rule, give sort a compare function. The function (a, b) => a - b is written in one line. It has no name. It gets two values, a and b, and returns a - b.

The sort method calls it on two items at a time. The result says which one goes first.

  • A negative number puts a first.
  • A positive number puts b first.
  • Zero means they are equal.

Some rules you will use often:

  • Low to high: (a, b) => a - b.
  • High to low: (a, b) => b - a.
  • Shortest first: (a, b) => a.length - b.length.

For two rules, the function needs a body in braces. Check the first rule. Use the second one only on a tie, as the if above does.

Above, the first rule compares the last digits, a % 10 and b % 10. Numbers with the same last digit then go from small to large.

The localeCompare method compares two strings. It gives a negative number when a comes first from A to Z.

The sort method changes the array itself. To keep the original, sort a copy made with words.slice().


Your task

A pet shop sells toys. Their prices are in prices. Sort prices from high to low.

The shop's pets are in names. Sort names by their last letter, in alphabetical order. Names with the same last letter go from A to Z.

The code already prints both, one item per line.

Expected output:

30
12
8
5
Bella
Luna
Bo
Coco
Max
Rex
STEP 1 OF 4
    Ctrl + Enter to check

    JAVASCRIPT · DESTRUCTURING, SORTING & BUILT-INS

    Custom Sorting in JavaScript, explained

    Why the default sort isn't enough

    Calling sort() with nothing inside works for text, which it puts from A to Z. For numbers it does something surprising: it turns them into text first and compares the text.

    console.log([10, 9, 1].sort());
    console.log([10, 9, 1].sort((a, b) => a - b));
    
    [ 1, 10, 9 ]
    [ 1, 9, 10 ]
    

    The first line is wrong for numbers, because the text "10" comes before "9". The second line fixes it with a compare function, and the same tool lets you sort in any order you like: the highest score first, the shortest word first, and so on.

    How a compare function works

    A compare function is a small function you give to sort. (a, b) => a - b is written in one line and has no name. It gets two items, a and b, and returns a number. sort calls it on two items at a time, and the number says which one goes first.

    • A negative number puts a first.
    • A positive number puts b first.
    • Zero means they are equal.

    Rules you will use often:

    • Low to high: (a, b) => a - b
    • High to low: (a, b) => b - a
    • Shortest first: (a, b) => a.length - b.length

    For high to low, think of two prices where b is bigger. Then b - a is positive, and a positive result puts b first.

    Two rules

    When one rule isn't enough, the function needs a body in braces. Check the first rule. Use the second one only on a tie.

    let nums = [25, 13, 5, 41, 33];
    
    nums.sort((a, b) => {
        if (a % 10 !== b % 10) {
            return a % 10 - b % 10;
        }
        return a - b;
    });
    console.log(nums);
    
    [ 41, 13, 33, 5, 25 ]
    

    The first rule compares the last digits, a % 10 and b % 10. Only when they are the same does the function reach return a - b, which puts the smaller number first.

    Comparing text with localeCompare

    You can't subtract strings. The method localeCompare does the job: x.localeCompare(y) gives a negative number when x comes before y from A to Z, a positive number when it comes after, and 0 when they are equal. That is exactly what a compare function must return.

    sort changes the array itself

    The sort method rearranges the array it is called on, and it returns that same array. To keep the original order, sort a copy made with slice():

    let words = ["pear", "fig", "banana", "kiwi"];
    console.log(words.slice().sort((a, b) => a.length - b.length));
    console.log(words);
    
    [ 'fig', 'pear', 'kiwi', 'banana' ]
    [ 'pear', 'fig', 'banana', 'kiwi' ]
    

    Items that compare as equal keep their original order, because sort is stable.

    The lesson's task

    A pet shop has prices and names. Sort prices from high to low, and sort names by their last letter, with names that share a last letter going from A to Z. The loops that print both are already in the starter code.

    The prices need one rule, b - a. The names need two. Inside the function, take the last letter of each name: it sits at index length - 1. If the two last letters differ, return their localeCompare. Otherwise return a.localeCompare(b), which puts Max before Rex.

    let prices = [12, 5, 30, 8];
    let names = ["Rex", "Luna", "Bella", "Max", "Bo", "Coco"];
    
    prices.sort((a, b) => b - a);
    for (let price of prices) {
        console.log(price);
    }
    
    names.sort((a, b) => {
        let lastA = a[a.length - 1];
        let lastB = b[b.length - 1];
        if (lastA !== lastB) {
            return lastA.localeCompare(lastB);
        }
        return a.localeCompare(b);
    });
    for (let name of names) {
        console.log(name);
    }
    

    It prints:

    30
    12
    8
    5
    Bella
    Luna
    Bo
    Coco
    Max
    Rex
    

    Common mistakes

    • Sorting numbers without a compare function. [10, 9, 1].sort() gives [1, 10, 9].
    • Swapping a and b. a - b sorts low to high, b - a high to low.
    • Dropping the second rule. With only the last-letter comparison, ties keep their original order and the names come out as Luna, Bella, Bo, Coco, Rex, Max. Rex precedes Max only because it was first in the array.
    • Using return a < b. A compare function must return a number, not a boolean.

    Key takeaways

    • Give sort a compare function of a and b; a negative result puts a first.
    • Use a - b for low to high and b - a for high to low.
    • For two rules, return the first rule's result when it isn't a tie, and fall back to the second rule otherwise.
    • Compare text with localeCompare.
    • sort changes the array; copy it with slice() to keep the original.
    Keep going with JavaScript500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free