Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Сортування масиву чисел». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Треба завжди передавати функцію порівняння: `arr.sort((a, b) => a - b)` для зростання і `arr.sort((a, b) => b - a)` для спадання. Без компаратора `sort()` приводить елементи до рядків і сортує лексикографічно, тому `[10, 1, 3, 20]` перетворюється на `[1, 10, 20, 3]`. Компаратор має повертати від'ємне число, якщо `a` йде раніше, додатне, якщо раніше йде `b`, і нуль, якщо порядок не важливий. `sort()` мутує масив і повертає його ж, тож коли оригінал потрібен незмінним, сортуйте копію: `[...arr].sort((a, b) => a - b)` або `arr.toSorted((a, b) => a - b)`.** ```javascript const numbers = [10, 1, 3, 20]; numbers.sort(); // [1, 10, 20, 3] wrong: string order numbers.sort((a, b) => a - b); // [1, 3, 10, 20] correct ``` **Ключове:** `sort()` за замовчуванням сортує рядки, тому для чисел компаратор `(a, b) => a - b` обов'язковий.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Щоб відсортувати числа за зростанням, викликайте `sort()` з функцією порівняння: `arr.sort((a, b) => a - b)`.** Без компаратора метод приводить елементи до рядків і шикує їх за алфавітом, тому число `10` опиняється перед `3`, і це найпоширеніша помилка на співбесідах. ## Теорія ### TL;DR - За зростанням: `arr.sort((a, b) => a - b)`. - За спаданням: `arr.sort((a, b) => b - a)`. - Без компаратора `sort()` порівнює **рядкові** представлення елементів. - Компаратор повертає від'ємне, додатне або нуль, і саме цим задає порядок. - `sort()` мутує вихідний масив і повертає посилання на нього. - Немутуючий варіант: `[...arr].sort(cmp)` або `arr.toSorted(cmp)` (ES2023). ### Швидкий приклад ```javascript const numbers = [10, 1, 3, 20]; numbers.sort((a, b) => a - b); console.log(numbers); // [1, 3, 10, 20] ``` ### Помилка новачків: sort() без компаратора ```javascript const numbers = [10, 1, 3, 20]; numbers.sort(); console.log(numbers); // [1, 10, 20, 3], string sorting ``` За замовчуванням `sort()` приводить елементи до рядків і сортує їх **у лексикографічному порядку**, тобто посимвольно за кодами UTF-16. Саме тому `"10"` йде перед `"2"`: перший символ `"1"` менший за `"2"`, і решта цифр уже не має значення. Важливо: сам масив при цьому не перетворюється на масив рядків, у ньому лишаються числа. До рядків зводяться лише ключі порівняння, тому в консолі ви бачите числа, просто розставлені «за алфавітом». ### Правильний спосіб: функція порівняння ```javascript const numbers = [10, 1, 3, 20]; numbers.sort((a, b) => a - b); console.log(numbers); // [1, 3, 10, 20] ``` Функція `(a, b) => a - b` каже рушію, **як порівнювати числа**: - якщо `a - b` менше за 0, то `a` йде раніше; - якщо `a - b` більше за 0, то раніше йде `b`; - якщо `a - b` дорівнює 0, порядок не змінюється. | Значення компаратора | Що означає | | --- | --- | | Від'ємне | `a` ставимо перед `b` | | Додатне | `b` ставимо перед `a` | | Нуль | елементи рівні, порядок зберігається | Починаючи з ES2019, `sort()` **стабільний**: елементи, для яких компаратор повернув нуль, зберігають вихідний взаємний порядок. Це дозволяє сортувати в кілька проходів, наприклад спочатку за ім'ям, потім за віком. ### Спадання і сортування без мутації Сортування за спаданням, це той самий компаратор навпаки: ```javascript const numbers = [1, 3, 10, 20]; numbers.sort((a, b) => b - a); console.log(numbers); // [20, 10, 3, 1] ``` Якщо вихідний масив чіпати не можна, сортуйте копію: ```javascript const arr = [5, 2, 9, 1]; const sorted = [...arr].sort((a, b) => a - b); console.log(sorted); // [1, 2, 5, 9] console.log(arr); // [5, 2, 9, 1], the original is untouched ``` У сучасних рушіях є готовий немутуючий метод: ```javascript const sorted = arr.toSorted((a, b) => a - b); // ES2023, returns a new array ``` Це особливо важливо в React і подібних бібліотеках: `state.items.sort(...)` змінить той самий об'єкт, посилання не зміниться і перерендеру не буде. ### Сусідні випадки: рядки та об'єкти Той самий принцип працює для будь-яких даних, змінюється лише компаратор: ```javascript // numbers as strings: convert before comparing ['10', '9', '2'].sort((a, b) => Number(a) - Number(b)); // ['2', '9', '10'] // text with correct alphabetical order ['яблуко', 'абрикос', 'їжа'].sort((a, b) => a.localeCompare(b, 'uk')); // objects by field const users = [{ name: 'Bob', age: 31 }, { name: 'Alice', age: 25 }]; users.sort((a, b) => a.age - b.age); // Alice first ``` Для великих чисел, що не влазять у `Number`, віднімання поверне `BigInt` або втратить точність, тому там пишуть явне порівняння: ```javascript arr.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0)); ``` ### Коротко | Задача | Код | Результат | | --- | --- | --- | | За зростанням | `arr.sort((a, b) => a - b)` | `[1, 2, 3, 4]` | | За спаданням | `arr.sort((a, b) => b - a)` | `[4, 3, 2, 1]` | | Без зміни вихідного масиву | `[...arr].sort(...)` | новий відсортований масив | | Без зміни, сучасний синтаксис | `arr.toSorted(...)` | новий відсортований масив | > **Підсумок:** щоб відсортувати числа за зростанням, завжди передавайте функцію порівняння: `arr.sort((a, b) => a - b)`. ### Типові помилки - **Викликати `sort()` без аргументів для чисел.** Це лексикографічне сортування, і на масивах, де є і однозначні, і двозначні числа, результат майже завжди неправильний. - **Повертати з компаратора `true` або `false`.** Наприклад `arr.sort((a, b) => a > b)`: булеве значення зводиться до 1 або 0, «менше» рушій ніколи не отримує, і порядок виходить непередбачуваним. Компаратор має повертати число зі знаком. - **Забувати, що `sort()` мутує.** Метод змінює вихідний масив і повертає його ж, а не копію. Для чужих даних, props і стану спершу копіюйте. - **Сортувати масив з `NaN`.** Будь-яке віднімання з `NaN` дає `NaN`, компаратор фактично повертає «невідомо», і порядок стає сміттєвим. Такі значення треба відфільтрувати заздалегідь. - **Не враховувати `undefined` і дірки.** Значення `undefined` завжди йдуть у кінець, а порожні позиції розрідженого масиву ще далі, і компаратор для них не викликається. - **Порівнювати текст через `a - b` або `a > b`.** Для рядків з літерами поза ASCII правильний порядок дає `localeCompare` з потрібною локаллю.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.