Execute Program

JavaScript Arrays: Sort

Welcome to the Sort lesson!

JavaScript arrays' `.sort` puts the elements in order. However, there are important caveats to its use.

This lesson is shown as static text below. However, it's designed to be used interactively. Click the button below to start!

  • The .sort method puts elements in order. We can use it to sort an array of strings alphabetically.

  • >
    const strings = ['c', 'a', 'b'];
    strings.sort();
    strings;
    Result:
    ['a', 'b', 'c']Pass Icon
  • .sort modifies the array. We can see that in the example above: we sorted the array, then looked at it, and its content had changed. However, .sort also returns the array to us.

  • >
    const strings = ['c', 'a', 'b'];
    strings.sort();
    Result:
    ['a', 'b', 'c']Pass Icon
  • Often, we want a sorted copy of an array without changing the original. We can use .slice to copy the array, then sort the copy.

  • >
    const originalStrings = ['c', 'a', 'b'];
    const sortedStrings = originalStrings.slice().sort();
    sortedStrings;
    Result:
    ['a', 'b', 'c']Pass Icon
  • Note: this code example reuses elements (variables, etc.) defined in earlier examples.
    >
    originalStrings;
    Result:
    ['c', 'a', 'b']Pass Icon
  • JavaScript often converts values in surprising ways. For example, 10 > 3 is true, but '10' < '3' is also true. This is because strings are compared character by character. The comparison ends as soon as two characters differ. '1' < '3', so '10' < '3'. The '0' in '10' is never even examined.

  • >
    '3' > '10';
    Result:
    truePass Icon
  • >
    '200' > '3';
    Result:
    falsePass Icon
  • .sort converts the array's elements to strings, then compares them. Because it compares strings, it inherits the comparison problem above.

  • This makes JavaScript's .sort unsafe for numbers and most other data. Most other programming languages don't have this problem, so be careful!

  • >
    [3, 10].sort();
    Result:
  • >
    [3, 10, 200].sort();
    Result:
    [10, 200, 3]Pass Icon
  • There's a way to fix this problem. We can write our own comparison function, then give it to .sort.

  • The .sort function will call our comparison function repeatedly. Each time, our function gets two array elements (a, b) as arguments and returns:

    • 0 if the two elements are equal.
    • A number greater than zero if a is greater.
    • A number smaller than zero if b is greater.
  • To start, .sort will call our function with the values at indexes 1 and 0 in the array. Then it will continue to pass other pairs of array elements as it determines what the sorted order should be.

  • Our comparison function only needs to determine which of two elements is greater, which is a relatively simple problem. By calling our comparison function over and over again, .sort eventually solves the more difficult problem of sorting the entire array.

  • >
    [10, 200, 3].sort((a, b) => {
    if (a === b) {
    return 0;
    } else if (a > b) {
    return 1;
    } else {
    return -1;
    }
    });
    Result:
    [3, 10, 200]Pass Icon
  • The above comparison function is very wordy. Fortunately, there's a shorthand that we can use. It relies on a trick:

    • If a === b, then a - b === 0.
    • If a > b, then a - b > 0.
    • If a < b, then a - b < 0.
  • >
    3 - 10 > 0;
    Result:
  • >
    10 - 3 > 0;
    Result:
  • Now here's the trick: our callback function can return a - b. According to the three cases outlined above, a - b will correctly return a positive number, negative number, or 0, which is exactly what .sort wants.

  • >
    [10, 200, 3].sort((a, b) => a - b);
    Result:
    [3, 10, 200]Pass Icon
  • We can use the comparison function for more than just numbers. For example, we can sort arrays by their lengths.

  • >
    [[0, 0], [], [0, 0, 0], [0]].sort((a, b) => a.length - b.length);
    Result:
    [[], [0], [0, 0], [0, 0, 0]]Pass Icon
  • We can even sort objects by a property.

  • >
    const users = [
    {name: 'Amir', loginAttempts: 5},
    {name: 'Betty', loginAttempts: 3}
    ];
    users.sort((user1, user2) => {
    return user1.loginAttempts - user2.loginAttempts;
    }).map(user => user.name);
    Result:
    ['Betty', 'Amir']Pass Icon