Skip to Content
Course content

206: Locale-Aware Sorting and Comparison

Click on the "Edit" button in the top corner of the screen to edit your slide content.

For a long time, I just assumed Array.prototype.sort() worked the way I expected it to. You give it a list of strings, it puts them in alphabetical order, and you move on with your day. But if you've ever built an app for a global audience, you've likely run into the moment where you realize that "alphabetical order" is a much more complicated concept than the computer understands by default.

The ASCII Trap

The problem is that by default, JavaScript sorts strings by comparing their UTF-16 code unit values. To the engine, it's not comparing letters; it's comparing numbers. This works fine for a list of all-lowercase English words, but it falls apart the second you introduce mixed casing or accented characters. Take a look at this:

const names = ['Zoe', 'apple', 'Áaron', 'Bob'];
names.sort();
console.log(names); // ['Bob', 'Zoe', 'apple', 'Áaron']

If you're looking at that result, you're probably thinking, "Wait, why is apple after Zoe?" and "Why is Áaron at the very end?" It's because uppercase letters have lower code values than lowercase letters, and accented characters are tucked away far further down the character map. In a real-world user interface, this looks like a bug. No user expects their contact list to be sorted by the internal numeric value of a character encoding.

The Quick Fix: localeCompare

The easiest way to fix this is by providing a comparator function to sort() using the localeCompare() method. This method is built specifically to handle the linguistic rules of a given language. Instead of comparing raw numbers, it asks the environment how these strings should actually be ordered.

const names = ['Zoe', 'apple', 'Áaron', 'Bob'];
names.sort((a, b) => a.localeCompare(b));
console.log(names); // ['apple', 'Áaron', 'Bob', 'Zoe']

Suddenly, the list makes sense. localeCompare handles the casing and the accent on "Áaron" correctly. If you're dealing with a small array, this is usually all you need. It's concise and it gets the job done without much fuss.

Scaling with Intl.Collator

However, if you're sorting a list of five thousand rows in a data table, calling localeCompare inside the sort loop is a performance killer. Every single time the sort algorithm compares two elements, it has to initialize the locale settings for that comparison. It's a lot of overhead for a repetitive task.

This is where Intl.Collator comes in. Think of it as a "pre-configured" version of localeCompare. You create the collator instance once, and then you use its compare method. I always reach for this when performance matters or when I need fine-grained control over the sorting logic.

const names = ['Zoe', 'apple', 'Áaron', 'Bob'];
const collator = new Intl.Collator('en', { sensitivity: 'base', numeric: true });
names.sort(collator.compare);
console.log(names);

The real power here is in the options object. By setting sensitivity: 'base', I can tell JavaScript to ignore accents and case entirely (treating 'a' and 'Á' as the same letter). And numeric: true is a lifesaver—it ensures that "Item 2" comes before "Item 10". Without it, you get the classic "1, 10, 2" sorting nightmare because "10" starts with "1", which comes before "2".

Between the two, localeCompare is great for the "one-off" sort, but Intl.Collator is the professional tool for production-grade lists. It's cleaner, faster, and gives you the control you need to make sure your UI doesn't frustrate users from different parts of the world.




📋 Practical Task

International City Directory Sort

You are building a city directory for a travel app. The current implementation uses a naive .sort(), which is causing cities like "Örebro" and "Zürich" to appear at the end of the list, and "City 10" to appear before "City 2".

Your Task: Rewrite the sorting logic using Intl.Collator to ensure the list is sorted linguistically and numerically.

const cities = [
  "Zürich",
  "appleton",
  "Örebro",
  "City 2",
  "City 10",
  "Berlin",
  "city 1"
];

// FIX THIS LINE:
cities.sort(); 

console.log(cities); 
// Expected output: ["appleton", "Berlin", "city 1", "City 2", "City 10", "Örebro", "Zürich"] 
// (Note: exact order of a/B/c may vary by locale, but numeric and accented logic must be correct)
Rating
0 0

There are no comments for now.

to be the first to leave a comment.