Introduction
Welcome to the first lesson in our module on Sorting and Binary Search. Sorting data is a fundamental operation in computer science, not just for presenting information in a human-readable order, but as a powerful prerequisite for many advanced algorithms. Often, a complex search or processing problem can be simplified dramatically by first sorting the input.
In this lesson, we will focus on mastering TypeScript's built-in sort method to handle common scenarios you'll encounter in algorithmic problems. We will cover how to write custom comparator functions to correctly sort numbers, how to implement multi-key sorting for complex objects or tuples, and the important concept of sort stability. Given your extensive front-end development experience, you are likely familiar with Array.prototype.sort(), so we will build on that foundation to establish a robust and principled approach for its use in algorithm design.
The sort() Comparator
As you know, Array.prototype.sort() is a powerful tool, but it has a quirk that can easily lead to bugs if you're not careful: by default, it sorts elements lexicographically (as strings).
const numbers = [10, 2, 1, 100];
numbers.sort();
console.log(numbers); // Output: [1, 10, 100, 2]
This is clearly not the numerical order we want. To sort elements based on a custom logic, we must provide a comparator function. This function takes two arguments, a and b, and must return a number that dictates their relative order.
To understand the contract of this comparator, let's watch a brief and clear explanation.
Algorithms: Sort An Array with Comparator
The HackerRank video "Algorithms: Sort An Array with Comparator" provides a great primer on this topic. Please watch the first part where the presenter explains why a comparator is needed and what its return values signify.
Focus on the segment from this explanation of the comparator's purpose and the meaning of returning a negative, zero, or positive value.
To summarize the key rules:
- Return a negative value (
< 0):ashould come beforeb. - Return a positive value (
> 0):bshould come beforea. - Return zero (
0):aandbare considered equal for sorting purposes; their relative order might not change (we'll discuss this more under "stability").
For sorting numbers in ascending order, this leads to a very common and concise pattern: (a, b) => a - b.
- If
a < b,a - bis negative, soacomes first. - If
a > b,a - bis positive, sobcomes first. - If
a === b,a - bis zero.
For descending order, you simply reverse the subtraction: (a, b) => b - a.
Sorting by Multiple Criteria
In many problems, you'll need to sort by a primary criterion, and then use a secondary criterion to break ties. For instance: "sort players by score descending, then by name ascending."
The standard way to implement this is with a single comparator function that chains these comparisons. The logic is:
- Compare
aandbon the primary key. - If the primary keys are not equal, you've found the correct order. Return the result of the comparison.
- If the primary keys are equal, return the result of comparing them on the secondary key.
- This pattern can be extended to tertiary keys and beyond.
The following video demonstrates this "fall back" logic clearly.
Algorithms: Sort An Array with Comparator
Continuing with the same HackerRank video, let's see how this tie-breaking logic is implemented.
Watch the section from the implementation, which first shows sorting by a primary key (score) and then adds a secondary key (name) to handle ties.
This leads to an elegant and highly readable pattern in TypeScript/JavaScript, often using the logical OR (||) operator for short-circuiting:
// Primary: score descending. Secondary: name ascending.
players.sort((a, b) => {
// Primary comparison
const scoreDifference = b.score - a.score;
if (scoreDifference !== 0) {
return scoreDifference;
}
// Secondary comparison (if scores are tied)
return a.name.localeCompare(b.name);
});
// A more concise version using short-circuiting:
players.sort((a, b) => (b.score - a.score) || a.name.localeCompare(b.name));
The expression (b.score - a.score) evaluates to a non-zero number if the scores are different, and the || operator returns this first "truthy" (non-zero) value. Only if b.score - a.score is 0 ("falsy") does the expression proceed to evaluate and return the result of the localeCompare.
Let's look at a complete example from a typical LeetCode problem.
1356. Sort Integers by The Number of 1 Bits - In-Depth Explanation
The problem "Sort Integers by The Number of 1 Bits" requires sorting an array of numbers first by the count of 1s in their binary representation (ascending), and then by their numerical value (ascending) if the bit counts are equal. This is a classic multi-key sorting problem.
First, read the problem and intuition to understand the two sorting criteria. Then, carefully study the provided TypeScript solution. Pay close attention to how the comparator function is structured to handle the primary and secondary sort conditions using the short-circuiting || operator. You can find it by searching for the function sortByBits within the TypeScript code.
Understanding Sort Stability
The concept of a stable sort is an important property of sorting algorithms. A sorting algorithm is stable if it preserves the original relative order of elements that have equal sort keys.

Why does this matter?
- Predictability: It makes the behavior of your code easier to reason about.
- Simplified Multi-key Sorting: With a stable sort, you can sort by multiple criteria by performing multiple sorts in reverse order of key priority. To sort by score (primary) then name (secondary), you could:
- Sort by name.
- Then, sort by score.
Because the second sort is stable, any players with the same score will remain in their name-sorted order.
Fortunately, you can rely on this behavior in modern environments.
TypeScript for DSA | DSA | AlgoMaster.io
The "AlgoMaster.io" guide has a quick but important note on this topic.
Please read the section on sorting, focusing on the note about stability under the heading Sorting and Comparators.
As the text confirms, since the ES2019 specification, Array.prototype.sort() is guaranteed to be stable. While the multi-sort trick is good to know, the single chained comparator we saw earlier is generally more efficient and explicit.
A Practical Example: Sorting Dictionary Values
A common task is to sort the entries of an object or Map by their values. Since objects don't have an inherent order, the process involves converting the object into an array, sorting it, and optionally converting it back.

The steps are as follows:
Object.keys(cityPopulation)gets an array of the keys (['Chicago', 'NewYork', 'LosAngeles'])..map(city => [city, cityPopulation[city]])transforms this array of keys into an array of[key, value]tuples..sort((a, b) => a[1] - b[1])sorts this array of tuples based on the second element of each tuple (the population), which isa[1]andb[1].- Finally,
forEachis used to build a new object from the sorted tuples.
Conclusion
In this lesson, we formalized the use of TypeScript's Array.prototype.sort for algorithmic problem-solving. We've established a solid foundation for one of the most common prerequisite steps in algorithms.
Here are the key takeaways:
- Always provide a custom comparator function when sorting anything other than strings. For numbers, use
(a, b) => a - bfor ascending order and(a, b) => b - afor descending. - The comparator's return value (
<0,0,>0) dictates the final ordering of elementsaandb. - For multi-key sorting, use a single comparator that checks the primary key first, and only proceeds to the secondary key if the primary keys are tied. The logical OR (
||) operator provides a concise way to chain these checks. - Modern JavaScript engines provide a stable sort, meaning elements with equal keys retain their original relative order.
In our next lesson, we will explore the first of many applications of this skill, answering the question: "When can sorting replace a more complicated search with a structured scan?" You'll see how sorting unlocks powerful and efficient patterns for solving a wide range of problems.
Can't find a good explanation? Sign up and we'll make it for you
Sign up