sort - метод массива для сортировки. Он полезен, но у него есть два важных нюанса:
- по умолчанию
sort()сортирует элементы как строки sort()изменяет исходный массив
Чтобы правильно сортировать числа, почти всегда нужен compare function.
sort по умолчанию сортирует как строки
const nums = [1, 2, 10, 21];
nums.sort();
console.log(nums); // [1, 10, 2, 21]
Так произошло потому, что значения сравниваются как строки: “10” идет перед “2”.
Правильная сортировка чисел: compare function
sort может принимать функцию сравнения:
arr.sort((a, b) => a - b);
По возрастанию
const nums = [1, 2, 10, 21];
nums.sort((a, b) => a - b);
console.log(nums); // [1, 2, 10, 21]
По убыванию
const nums = [1, 2, 10, 21];
nums.sort((a, b) => b - a);
console.log(nums); // [21, 10, 2, 1]
Как работает compare function
Функция сравнения получает два элемента a и b и должна вернуть число:
< 0-aидет раньшеb> 0-aидет позжеb0- порядок междуaиbне меняется (или не важен)
Для чисел удобно использовать a - b и b - a.
sort изменяет массив: как сортировать без изменения исходного
sort мутирует массив. Если исходный массив нужен дальше без изменений, сначала делается копия.
Через slice():
const nums = [3, 1, 10, 2];
const sorted = nums.slice().sort((a, b) => a - b);
console.log(sorted); // [1, 2, 3, 10]
console.log(nums); // [3, 1, 10, 2]
Сортировка объектов по числовому полю
const users = [
{ id: 3, name: "Kim" },
{ id: 1, name: "Sam" },
{ id: 2, name: "Alex" }
];
const byId = users.slice().sort((a, b) => a.id - b.id);
console.log(byId);
// [{ id: 1, name: "Sam" }, { id: 2, name: "Alex" }, { id: 3, name: "Kim" }]
Сортировка строк: localeCompare
Для строк часто используют localeCompare, чтобы сравнение было корректнее для разных языков.
const names = ["Zoe", "Ann", "Eva"];
const sorted = names.slice().sort((a, b) => a.localeCompare(b));
console.log(sorted);
Осторожно с “грязными” данными
Если в массиве встречаются строки и числа, сравнение может дать неожиданные результаты. Лучше приводить данные к одному типу заранее.
const values = ["10", 2, "3", 1];
const nums = values.map(v => Number(v));
const sorted = nums.sort((a, b) => a - b);
console.log(sorted); // [1, 2, 3, 10]
Если Number(v) может дать NaN, стоит проверять это отдельно (см. шаг про NaN).
Частые ошибки
1) sort() для чисел без compare function
const nums = [2, 11, 3];
nums.sort();
console.log(nums); // [11, 2, 3]
2) Неожиданное изменение исходного массива
const nums = [3, 1, 2];
const sorted = nums.sort((a, b) => a - b);
console.log(sorted); // [1, 2, 3]
console.log(nums); // [1, 2, 3]
Если нужен исходный порядок, нужна копия:
const nums = [3, 1, 2];
const sorted = nums.slice().sort((a, b) => a - b);
console.log(sorted); // [1, 2, 3]
console.log(nums); // [3, 1, 2]
Что стоит запомнить
sort()по умолчанию сортирует как строки.- Для чисел нужен compare function:
(a, b) => a - b. sort()меняет исходный массив, для безопасной сортировки нужна копия.- Для объектов сортируют по полю:
(a, b) => a.field - b.field.