Перейти к содержимому
Теория · Методы массивов · урок 7 из 12

Сортировка

Последний работник у нашего конвейера — сортировщик. Он берёт два ящика, сравнивает их и решает, какой поставить раньше. Так, пара за парой, он расставляет по порядку всю ленту.

Метод sort и есть такой сортировщик: он расставляет элементы массива по порядку. Со словами он работает так, как ожидается, а с числами — нет:

JavaScript
const words = ["pear", "apple", "fig"];
words.sort();
console.log(words); // [ 'apple', 'fig', 'pear' ]

const nums = [25, 100, 3];
nums.sort();
console.log(nums); // [ 100, 25, 3 ]

Давайте разберём, что произошло:

  1. Слова встали по алфавиту: apple, fig, pear.
  2. Числа встали в странном порядке: 100 оказалось первым, хотя оно самое большое.

Почему так вышло с числами, часто спрашивают на собеседовании. Ответ — в том, как sort сравнивает элементы без подсказки.

Сравнение как строк

Без аргумента sort переводит каждый элемент в строку и сравнивает строки символ за символом, как слова в словаре. Строка "100" начинается с "1", а "1" меньше "2" и "3". Поэтому 100 встаёт первым, хотя как число оно самое большое.

Строка "10" тоже меньше строки "9": "10" < "9" даёт true. Строки сравниваются по кодам символов, поэтому заглавные буквы идут раньше строчных: ["b", "A", "a"].sort() даёт [ 'A', 'a', 'b' ].

Функция сравнения

Чтобы сравнивать числа как числа, сортировщику дают правило. В sort передают функцию сравнения. sort вызывает её с двумя элементами a и b и смотрит на знак результата:

  • отрицательное число — a встаёт раньше b;
  • положительное число — b встаёт раньше a;
  • 0 — порядок этих двух элементов не меняется.

Разность a - b отрицательна, когда a меньше. Поэтому (a, b) => a - b расставляет числа по возрастанию, а (a, b) => b - a — по убыванию:

JavaScript
nums.sort((a, b) => a - b);
console.log(nums.join(" ")); // 3 25 100

nums.sort((a, b) => b - a);
console.log(nums.join(" ")); // 100 25 3

Возьмём пару 25 и 3 при сортировке по возрастанию. Разность 25 - 3 равна 22, это положительное число, поэтому 3 встаёт раньше 25.

Сравнивать можно что угодно, например длину строк: words.sort((a, b) => a.length - b.length).

Функция сравнения должна возвращать число: отрицательное, положительное или 0. Функция (a, b) => a > b возвращает true или false. sort читает их как 1 и 0, и отрицательного числа не получает никогда. С ней порядок бывает неверным: в Node.js [3, 1, 2] так и остаётся [3, 1, 2].

sort и toSorted

Здесь аналогия с сортировщиком перестаёт работать. Настоящий сортировщик мог бы выставить ящики на новую ленту, а sort новый массив не создаёт. Он переставляет элементы того массива, у которого вызван.

sort меняет массив

sort меняет массив на месте, как push и pop. sort возвращает тот же самый массив, а не копию.

toSorted возвращает копию

Метод toSorted принимает ту же функцию сравнения, но возвращает отсортированную копию, а исходный массив не трогает. Метод появился в языке в 2023 году; его знают Node.js 22 и браузеры, выпущенные после середины 2023 года:

JavaScript
const scores = [70, 95, 80];
const ranked = scores.toSorted((a, b) => b - a);

console.log(ranked.join(" ")); // 95 80 70
console.log(scores.join(" ")); // 70 95 80

В ranked баллы стоят по убыванию, а в scores остался исходный порядок.

Частая ошибка

Результат sort сохранили в новую константу и ждали, что исходный массив останется прежним:

JavaScript
const prices = [30, 10, 20];
const sorted = prices.sort((a, b) => a - b); // ✗

console.log(prices.join(" "));

Ошибки нет, но программа выводит 10 20 30: sort переставил элементы самого prices. sorted и prices — два имени одного массива, и sorted === prices даёт true. Когда исходный порядок нужен дальше, пишите prices.toSorted((a, b) => a - b) или сортируйте копию [...prices].

Главное

  • Без аргумента sort сравнивает элементы как строки, поэтому 100 встаёт раньше 25.
  • Для чисел передают функцию сравнения: (a, b) => a - b по возрастанию, (a, b) => b - a по убыванию.
  • sort меняет сам массив и возвращает его же, а toSorted возвращает новый массив.

Подпишись, чтобы пройти курс

Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.

Войти другим способом