Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Чому sort() сортує числа й українські слова неправильно і як це виправити?

Без компаратора sort() перетворює елементи на рядки і порівнює їх за кодами символів UTF-16:

[10, 9, 1].sort();   // [1, 10, 9] - '10' < '9', бо '1' < '9'

Для чисел потрібна функція порівняння, що повертає від'ємне, нуль чи додатне число:

[10, 9, 1].sort((a, b) => a - b);        // [1, 9, 10]
users.sort((a, b) => b.age - a.age);     // за спаданням віку

Українські рядки. Порівняння за кодами UTF-16 ламає абетку: літери є, і, ї, ґ мають коди більші за я, бо в Unicode стоять поза основним блоком:

['яблуко', 'їжак', 'ґанок', 'гора', 'єнот'].sort();
// ['гора', 'яблуко', 'єнот', 'їжак', 'ґанок'] - неправильно

Правильно - Intl.Collator з українською локаллю:

const collator = new Intl.Collator('uk');
words.sort(collator.compare);
// ['гора', 'ґанок', 'єнот', 'їжак', 'яблуко']

users.sort((a, b) => collator.compare(a.name, b.name));

Корисні опції колатора:

  • numeric: true - «природне» сортування чисел у рядках: файл2 перед файл10;
  • sensitivity: 'base' - ігнорувати регістр і діакритику при порівнянні (зручно для пошуку збігів);
  • caseFirst: 'upper' - великі літери першими.

a.localeCompare(b, 'uk') дає той самий результат, але створює колатор при кожному виклику. Для сортування великих масивів один Intl.Collator значно швидший.

Інші факти про sort:

  • сортування змінює масив на місці і повертає той самий масив. Для копії - toSorted() (ES2023);
  • сортування стабільне (гарантовано з ES2019): елементи з однаковим ключем зберігають взаємний порядок. Тому сортування за кількома ключами можна робити послідовно, але простіше одним компаратором:
items.sort((a, b) => a.category.localeCompare(b.category, 'uk') || b.price - a.price);
  • компаратор має бути узгодженим: повертати true/false ((a, b) => a > b) - помилка. Результат залежить від рушія і може бути неправильним;
  • undefined завжди йдуть у кінець, компаратор для них не викликається.

Сортування на сервері й на клієнті має збігатися. Якщо список посторінково сортує база (з колацією uk), а клієнт досортовує сторінку через sort() без колатора, порядок «стрибатиме».

Докладніше в документації: Array.prototype.sort()

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання