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 та властивості з цілими числовими ключами. Хоча рядки також мають подібну структуру масиву, цей метод не підходить для їх застосування, оскільки рядки є незмінними.

автор: Bond

Як сортувати правильно

Найвідоміший сюрприз 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().

автор: NagarD

Порада

Метод sort() змінює вихідний масив і повертає відсортовану версію. Якщо вам потрібно зберегти початковий масив, зробіть його копію перед викликом методу.

автор: Bond
Порада

Щоб відсортувати елементи в масиві без змінення оригінального масиву, використовуйте toSorted().

автор: Bond
Порада

Ви можете передати функцію порівняння у метод sort(), яка визначає критерій сортування. Функція повинна приймати два аргументи (два елементи масиву) і повертати значення, яке вказує, який елемент повинен бути розташований перед іншим. Наприклад, для сортування чисел у порядку зростання можна використати:

array.sort(function(a, b) { return a - b; });
автор: Bond
Порада

Якщо ви хочете, щоб sort() не змінював початковий масив, а повертав копію масиву з поверхневим копіюванням, як це роблять інші методи масиву (наприклад, map()), використовуйте метод toSorted(). Або ви можете зробити поверхневу копію перед викликом sort(), використовуючи синтаксис розпилення або Array.from().

const numbers = [3, 1, 4, 1, 5]; // [...numbers] створює поверхневу копію, тому sort() не змінює початковий масив const sorted = [...numbers].sort((a, b) => a - b); sorted[0] = 10; console.log(numbers[0]); // 3

автор: Bond

Синтаксис

sort()
sort(compareFn)

Параметри

compareFn

Функція, яка визначає порядок сортування. Значення, що повертається, повинно бути числом, знак якого вказує на відносний порядок двох елементів: від'ємне, якщо a менше b, додатнє, якщо a більше b, і нуль, якщо вони рівні. NaN розглядається як 0.

Функція compareFn викликається з наступними аргументами:

  • a: Перший елемент для порівняння. Ніколи не буде undefined.

  • b: Другий елемент для порівняння. Ніколи не буде undefined.

Якщо пропущено, елементи масиву перетворюються на рядки, а потім сортуються відповідно до значення Unicode кожного символу.

автор: Bond

Повернення

reference

Посилання на вихідний масив, який був відсортований. Зверніть увагу, що масив сортується на місці, без створення копії.

автор: Bond

Переглядачі

Підтримка: стаціонарні переглядачі
Переглядач Google Chrome Mozilla Firefox Apple Safari Opera Microsoft EDGE
1 1 1 4 12
Підтримка: мобільні переглядачі
Переглядач Mobile Google Android Mobile Google Chrome Mobile Mozilla Firefox Mobile Apple Safari
4.4 18 4 1
Підтримка: серверні переглядачі
Переглядач Node.js Deno
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']
автор: Bond

Метод 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
автор: Bond

Використання sort() на розріджених масивах. Порожні слоти переміщуються до кінця масиву.

console.log(["a", "c", , "b"].sort()); // ['a', 'b', 'c', empty]
console.log([, undefined, "a", "b"].sort()); // ["a", "b", undefined, empty]
автор: Bond

Цей приклад демонструє, як метод sort() сортує елементи масиву як рядки, що може привести до неочікуваних результатів при сортуванні чисел. Додатково демонструється робота з функцією порівняння для правильного сортування чисел.

автор: Bond

Виклик 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' }
автор: Bond

Для сортування рядків з нелатинськими символами, наприклад, рядків з акцентованими символами (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é']
автор: Bond

Коментарі

Коментарів ще немає — будьте першим!

Відповідь для

Увійдіть — коментар з'явиться одразу, без капчі й очікування перевірки.

Пропозиція правки

Ваша версія — : після перевірки замінить чинну. Нова порада чи нотатка — з'явиться на сторінці після перевірки.

Ви гість — діють добові ліміти. Увійдіть, щоб пропонувати без капчі.

Ваша версія секції «»: після перевірки замінить чинну.

Ви гість — діють добові ліміти. Увійдіть, щоб пропонувати без капчі.

Ваша версія опису «»: після перевірки замінить чинну.

Ви гість — діють добові ліміти. Увійдіть, щоб пропонувати без капчі.

Зворотний зв'язок
Вхід