Sorting in JavaScript


In JavaScript, we can sort the elements of an array easily with a built-in method called the sort() function.

The default sort order is ascending, built upon converting the elements into strings, then comparing them lexicographically.


Array of strings:

When we use the sort() method, elements will be sorted in ascending order (A to Z) by default:

let teams = ['Real Madrid', 'Manchester Utd', 'Bayern Munich', 'Juventus'];

teams.sort(); 

// ['Bayern Munich', 'Juventus', 'Manchester Utd', 'Real Madrid']

Arrays of numbers:

Sorting numbers is unfortunately not that simple. If we apply the sort() method directly to a numbers array, we will see an unexpected result:

let numbers = [3, 23, 12];

numbers.sort(); // --> 12, 23, 3

By default, the sort() function sorts values as strings.

This works well for strings ("Apple" comes before "Banana").

However, if numbers are sorted as strings, "3" is bigger than "23", because "3" is bigger than "2".

Because of this, the sort() method will produce incorrect results when sorting numbers.


Solution: The Compare Function

Luckily, we can support the sort() method with a basic comparison function which will do the trick:

function(a, b) {return a - b}

When the sort() function compares two values, it sends the values to the compare function, and sorts the values according to the returned (negative, zero, positive) value:

  • If the result is negative a is sorted before b.
  • If the result is positive b is sorted before a.
  • If the result is 0 no changes are done with the sort order of the two values.

All we need to is using the compare function inside the sort() method:

let numbers = [3, 23, 12];

numbers.sort(function(a, b) {return a - b}); // --> 3, 12, 23

JavaScript gives us a way to make this code shorter using arrow functions:

numbers.sort(function(a, b) {return a - b});

// can be rewritten as:
numbers.sort((a, b) => {return a - b});

// and even as:
numbers.sort((a, b) => a - b);

If we want to sort the numbers in descending order, this time we need to subtract the second parameter (b) from the first one (a):

let numbers = [3, 23, 12];

numbers.sort((a, b) => b - a); // --> 23, 12, 3

Arrays of pairs:

Let's see another scenario when the comparison function is very useful: sorting an array, where each element is another array consisting of two numbers, ascending by the second values and in case of equality, descending by the first values:

let pairs = [[1, 3], [10, 1], [12, 1], [7, 5]];

//sort the array

// Desired outcome: pairs = [[12, 1], [10, 1], [1, 3], [7, 5]]

Here is how we would do that:

let pairs = [[1, 3], [10, 1], [12, 1], [7, 5]];

pairs.sort((a, b) => {
    if(a[1] == b[1]) {
        return b[0] - a[0];
    }
    return a[1] - b[1];
});

// pairs = [[12, 1], [10, 1], [1, 3], [7, 5]]

Time Complexity:

Sorting an array via sort() takes O(n * log n * C) time, where C is the time taken to compare two elements from the array.

It takes O(1) (constant time) to compare two numbers, therefore sorting an array of numbers takes O(n log n).

However, it takes O(L) to compare two strings, therefore sorting an array of strings takes O(n * log n * L), where L is the average length of the strings.


Space Complexity:

The sort() method sorts the elements of an array in place (transforms the array directly, using no auxiliary data structure), so the extra space used for this is O(1).


Assignment
Follow the Coding Tutorial and let's sort some arrays.


Hint
Look at the examples above if you get stuck.


Introduction

Sorting is a fundamental concept in computer science and programming. It involves arranging data in a particular order, typically ascending or descending. Sorting is crucial because it enhances the efficiency of other algorithms that require sorted data, such as search algorithms. Common scenarios where sorting is useful include organizing a list of names, arranging numerical data, and preparing data for binary search.

Understanding the Basics

Before diving into complex sorting algorithms, it's essential to understand the basic concepts. The sort() method in JavaScript is a built-in function that sorts the elements of an array. By default, it sorts elements as strings in ascending order. This default behavior can lead to unexpected results when sorting numbers, as they are compared lexicographically.

For example:

let numbers = [3, 23, 12];
numbers.sort(); // --> [12, 23, 3]

Here, "3" is considered greater than "23" because the comparison is based on the first character of the string representation of the numbers.

Main Concepts

To sort numbers correctly, we need to use a compare function. The compare function takes two arguments and returns a negative, zero, or positive value based on the comparison:

Example:

let numbers = [3, 23, 12];
numbers.sort((a, b) => a - b); // --> [3, 12, 23]

Examples and Use Cases

Let's explore some examples to understand how sorting works in different contexts:

Sorting Strings:

let teams = ['Real Madrid', 'Manchester Utd', 'Bayern Munich', 'Juventus'];
teams.sort(); // --> ['Bayern Munich', 'Juventus', 'Manchester Utd', 'Real Madrid']

Sorting Numbers in Descending Order:

let numbers = [3, 23, 12];
numbers.sort((a, b) => b - a); // --> [23, 12, 3]

Sorting Arrays of Pairs:

let pairs = [[1, 3], [10, 1], [12, 1], [7, 5]];
pairs.sort((a, b) => {
    if (a[1] === b[1]) {
        return b[0] - a[0];
    }
    return a[1] - b[1];
});
// --> [[12, 1], [10, 1], [1, 3], [7, 5]]

Common Pitfalls and Best Practices

When using the sort() method, it's essential to be aware of common pitfalls:

Best practices include:

Advanced Techniques

Advanced sorting techniques involve custom compare functions for complex data structures. For example, sorting an array of objects based on multiple properties:

let students = [
    { name: 'Alice', grade: 85 },
    { name: 'Bob', grade: 92 },
    { name: 'Charlie', grade: 85 }
];
students.sort((a, b) => {
    if (a.grade === b.grade) {
        return a.name.localeCompare(b.name);
    }
    return b.grade - a.grade;
});
// --> [{ name: 'Bob', grade: 92 }, { name: 'Alice', grade: 85 }, { name: 'Charlie', grade: 85 }]

Code Implementation

Here is a well-commented code snippet demonstrating the correct use of the sort() method:

let numbers = [3, 23, 12];

// Sorting numbers in ascending order
numbers.sort((a, b) => a - b); // --> [3, 12, 23]

// Sorting numbers in descending order
numbers.sort((a, b) => b - a); // --> [23, 12, 3]

// Sorting an array of pairs
let pairs = [[1, 3], [10, 1], [12, 1], [7, 5]];
pairs.sort((a, b) => {
    if (a[1] === b[1]) {
        return b[0] - a[0];
    }
    return a[1] - b[1];
});
// --> [[12, 1], [10, 1], [1, 3], [7, 5]]

Debugging and Testing

Debugging sorting functions involves checking the order of elements after sorting. Use console logs to verify the intermediate steps:

let numbers = [3, 23, 12];
numbers.sort((a, b) => a - b);
console.log(numbers); // --> [3, 12, 23]

Testing can be done using various test cases to ensure the sorting function works correctly:

let testCases = [
    { input: [3, 23, 12], expected: [3, 12, 23] },
    { input: [5, 2, 9, 1], expected: [1, 2, 5, 9] }
];
testCases.forEach(test => {
    let result = test.input.sort((a, b) => a - b);
    console.assert(JSON.stringify(result) === JSON.stringify(test.expected), `Test failed for input ${test.input}`);
});

Thinking and Problem-Solving Tips

When approaching sorting problems, consider the following strategies:

Conclusion

Sorting is a vital skill in programming, and mastering it can significantly improve your problem-solving abilities. By understanding the basics, avoiding common pitfalls, and practicing with various examples, you can become proficient in sorting data in JavaScript.

Additional Resources

For further reading and practice, consider the following resources: