JavaScript sort() — сортування масиву: числа, рядки, об'єкти
Опис
Метод sort() сортує елементи масиву на місці і повертає посилання на той же масив, але вже відсортований. За замовчуванням порядок сортування є зростаючим, він базується на перетворенні елементів у рядки, а потім порівнянні їх послідовностей значень кодових одиниць UTF-16.
У випадку, коли функція compareFn не задана, всі невизначені елементи масиву сортуються шляхом перетворення їх у рядки та порівняння рядків у порядку кодових одиниць UTF-16. Наприклад, "banana" передує "cherry". При числовому сортуванні 9 передує 80, але через перетворення чисел у рядки, "80" вище "9" у порядку Unicode. Усі невизначені елементи сортуються в кінець масиву.
Метод sort() зберігає порожні слоти. Якщо вихідний масив має розріджену структуру, порожні слоти переміщуються в кінець масиву та завжди йдуть після всіх невизначених елементів.
У випадку, коли надана функція compareFn, всі невизначені елементи масиву переміщаються в кінець масиву без виклику compareFn. Усі визначені елементи масиву сортуються відповідно до значення, яке повертає функція порівняння compareFn.
Отже, функція порівняння має таку форму:
function compareFn(a, b) {
if (a менше b за якимось критерієм упорядкування) {
return -1;
}
if (a більше b за критерієм упорядкування) {
return 1;
}
// a має бути рівним b
return 0;
}
Вимоги до порівняльника (compareFn) мають такі властивості, щоб гарантувати правильну поведінку сортування:
- Чистота (Pure): Порівняльник не вносить змін до об'єктів, які підлягають порівнянню, і не впливає на зовнішній стан. Це критично, оскільки невідомо, коли саме буде виконано порівняння. Отже, жоден окремий виклик не має створювати видимих змін в зовнішньому середовищі.
- Стабільність (Stable): Результат роботи порівняльника для однакових вхідних даних завжди має бути однаковим.
- Рефлексивність (Reflexive):
compareFn(a, a) === 0. - Антисиметричність (Anti-symmetric): Як
compareFn(a, b), так іcompareFn(b, a)або обидва дорівнюють 0, або мають протилежні значення. - Транзитивність (Transitive): Якщо
compareFn(a, b)іcompareFn(b, c)мають однаковий знак (або нульове значення), тоcompareFn(a, c)також має цей знак.
Ефективний порівняльник може повертати лише одне з трьох значень: 1, 0 або -1. Якщо він завжди повертає 0, це означає, що порядок масиву не зміниться, але порівняльник вважається надійним.
Для порівняння чисел замість рядків можна просто відняти b від a. Ось функція, що сортує масив у порядку зростання (за умови, що він не містить значень Infinity та NaN):
function compareNumbers(a, b) {
return a - b;
}
Метод sort() є універсальним. Він очікує, що значення this матиме властивість length та властивості з цілими числовими ключами. Хоча рядки також мають подібну структуру масиву, цей метод не підходить для їх застосування, оскільки рядки є незмінними.
Як сортувати правильно
Найвідоміший сюрприз sort(): без аргументів він порівнює елементи як рядки. Тому [1, 10, 2].sort() дає [1, 10, 2] — посимвольно «10» менше за «2», бо «1» < «2». Це не баг, а поведінка за стандартом.
Числа сортують функцією порівняння: (a, b) => a - b за зростанням, (a, b) => b - a за спаданням.
Об'єкти — порівнянням поля: users.sort((a, b) => a.age - b.age).
Українські рядки — через localeCompare: words.sort((a, b) => a.localeCompare(b, 'uk')). Звичайне порівняння розставляє «і», «ї» та «є» за кодами символів — не там, де їх шукає око.
І головне: sort() змінює сам масив, а не повертає копію. Потрібен незайманий оригінал — бери сучасний toSorted() або копіюй перед сортуванням: [...arr].sort().
- Порада
-
Метод
автор: Bondsort()змінює вихідний масив і повертає відсортовану версію. Якщо вам потрібно зберегти початковий масив, зробіть його копію перед викликом методу. - Порада
-
Щоб відсортувати елементи в масиві без змінення оригінального масиву, використовуйте
автор: BondtoSorted(). - Порада
-
Ви можете передати функцію порівняння у метод
sort(), яка визначає критерій сортування. Функція повинна приймати два аргументи (два елементи масиву) і повертати значення, яке вказує, який елемент повинен бути розташований перед іншим. Наприклад, для сортування чисел у порядку зростання можна використати:
автор: Bondarray.sort(function(a, b) { return a - b; }); - Порада
-
Якщо ви хочете, щоб
sort()не змінював початковий масив, а повертав копію масиву з поверхневим копіюванням, як це роблять інші методи масиву (наприклад,map()), використовуйте методtoSorted(). Або ви можете зробити поверхневу копію перед викликомsort(), використовуючи синтаксис розпилення абоArray.from().
автор: Bondconst numbers = [3, 1, 4, 1, 5]; // [...numbers] створює поверхневу копію, тому sort() не змінює початковий масив const sorted = [...numbers].sort((a, b) => a - b); sorted[0] = 10; console.log(numbers[0]); // 3
Синтаксис
sort()
sort(compareFn)
Параметри
compareFn-
Функція, яка визначає порядок сортування. Значення, що повертається, повинно бути числом, знак якого вказує на відносний порядок двох елементів: від'ємне, якщо
aменшеb, додатнє, якщоaбільшеb, і нуль, якщо вони рівні.NaNрозглядається як0.Функція
compareFnвикликається з наступними аргументами:a: Перший елемент для порівняння. Ніколи не будеundefined.b: Другий елемент для порівняння. Ніколи не будеundefined.
Якщо пропущено, елементи масиву перетворюються на рядки, а потім сортуються відповідно до значення Unicode кожного символу.
автор: Bond
Повернення
reference-
Посилання на вихідний масив, який був відсортований. Зверніть увагу, що масив сортується на місці, без створення копії.
автор: Bond
Переглядачі
| Переглядач | |||||
|---|---|---|---|---|---|
| 1 | 1 | 1 | 4 | 12 |
| Переглядач | ||||
|---|---|---|---|---|
| 4.4 | 18 | 4 | 1 |
| Переглядач | ||
|---|---|---|
| 0.10.0 | 1.0 |
Приклади
+ запропонувати свій приклад у пісочниці
Створення, відображення та сортування масиву.
const stringArray = ["Синій", "Горбатий", "Білуха"];
const numberArray = [40, 1, 5, 200];
const numericStringArray = ["80", "9", "700"];
const mixedNumericArray = ["80", "9", "700", 40, 1, 5, 200];
function compareNumbers(a, b) {
return a - b;
}
stringArray.join(); // 'Синій,Горбатий,Білуха'
stringArray.sort(); // ['Білуха', 'Синій', 'Горбатий']
numberArray.join(); // '40,1,5,200'
numberArray.sort(); // [1, 200, 40, 5]
numberArray.sort(compareNumbers); // [1, 5, 40, 200]
numericStringArray.join(); // '80,9,700'
numericStringArray.sort(); // ['700', '80', '9']
numericStringArray.sort(compareNumbers); // ['9', '80', '700']
mixedNumericArray.join(); // '80,9,700,40,1,5,200'
mixedNumericArray.sort(); // [1, 200, 40, 5, '700', '80', '9']
mixedNumericArray.sort(compareNumbers); // [1, 5, '9', 40, '80', 200, '700']
Метод sort() повертає посилання на початковий масив, тому зміни, внесені до повернутого масиву, також змінять початковий масив.
const numbers = [3, 1, 4, 1, 5];
const sorted = numbers.sort((a, b) => a - b);
// numbers і sorted - це обидва [1, 1, 3, 4, 5]
sorted[0] = 10;
console.log(numbers[0]); // 10
Використання sort() на розріджених масивах. Порожні слоти переміщуються до кінця масиву.
console.log(["a", "c", , "b"].sort()); // ['a', 'b', 'c', empty]
console.log([, undefined, "a", "b"].sort()); // ["a", "b", undefined, empty]
Цей приклад демонструє, як метод sort() сортує елементи масиву як рядки, що може привести до неочікуваних результатів при сортуванні чисел. Додатково демонструється робота з функцією порівняння для правильного сортування чисел.
Виклик sort() на об'єктах, які не є масивами.
const arrayLike = {
length: 3,
unrelated: "foo",
0: 5,
2: 4,
};
console.log(Array.prototype.sort.call(arrayLike));
// { '0': 4, '1': 5, length: 3, unrelated: 'foo' }
Для сортування рядків з нелатинськими символами, наприклад, рядків з акцентованими символами (e, é, è, a, ä тощо) або рядків інших мов, використовуйте метод String.prototype.localeCompare(). Ця функція може порівнювати такі символи так, що вони з'являються в правильному порядку.
const items = ["réservé", "premier", "communiqué", "café", "adieu", "éclair"];
items.sort((a, b) => a.localeCompare(b));
// items is ['adieu', 'café', 'communiqué', 'éclair', 'premier', 'réservé']
Коментарі
Коментарів ще немає — будьте першим!