Array.sort() в JavaScript
Давайте рассмотри такую ситуацию. Вы на собеседовании. И вам дали на рассмотрение множество строк.
const arr = [
"karachi",
"lahore",
"kolachi",
"islamabad"
]
И попросили отсортировать в алфавитном порядке.
Представим, что ваш шаг будет выглядеть так:
arr.sort((a, b) => {
return a < b;
});
Вам скажут, что это будет работать только с числами (на самом деле это не так), но не сработает для строк.
Следующий шаг, который вы, предположим, предпримете:
arr.sort((a, b) => {
return a.charAt(0) < b.charAt(0);
});
Вам скажут, что это будет работать только для первых символов (на самом деле это не так), тогда как будут сортироваться карачи и колачи, начинающиеся с k?
Ответа же вы не знаете.
Услышите вопрос, что такое a
и b
?
Возможно ответ будет таким: a
- это текущий элемент (элемент с индексом текущей итерации), а b
- следующий элемент (элемент с индексом текущей итерации + 1).
Но на самом деле все наоборот. a
- это следующий элемент, а b
- текущий элемент.
Затем вы услышите вопрос, изменяет ли сортировка исходный массив или возвращает новый массив?
Честно говоря, большую часть времени мы работаем с .map()
, .filter()
, .some()
и .every()
. Итак, мы знаем поведение этих методов. Так когда же в последний раз использовался .sort()
?
Он не изменяет исходный массив, скорее возвращает новый массив, подобный .map()
.
Но все наоборот, .sort()
изменяет исходный массив и возвращает ссылку на исходный массив, который теперь отсортирован.
Как на самом деле работает .sort()?
Array.sort()
принимает необязательную функцию сравнения в качестве аргумента.
Если мы не предоставляем никакой функции сравнения, метод сортировки преобразует все элементы non-undefined
в строку, а затем сравнивает их последовательности значений единиц кода UTF-16.
Что означает «сравнить их последовательности значений кодовых единиц UTF-16»?
Проще говоря, допустим, мы пишем символ a
, который в JavaScript кодируется как UTF-16. В десятичной системе счисления это значение будет равно 97
. Для b
это будет 98
. т.е.
A
= 65
B
= 66
C
= 67
и так далее.
Мы полагаем, вы знаете таблицу ASCII.
Таким образом, в основном массив строк будет автоматически отсортирован методом .sort()
правильно без передачи какой-либо функции сравнения.
В случае чисел поведение такое же;
const arr = [1, 30, 4, 21, 100000];
arr.sort();
console.log(arr);
// expected output: [1, 100000, 21, 30, 4]
Потому что каждое число сначала преобразуется в строку, а затем сравнивается с их значениями кодовых единиц UTF-16.
Но если мы предоставим функцию сравнения для сортировки по числам:
const arr = [1, 5, 3, 10, 7]
arr.sort((nextValue, prevValue) => {
// if returnValue > 0, move nextValue after the prevValue
// if returnValue < 0, move the nextValue before the prevValue
// if returnValue === 0, keep the original order, do not move any value
return nextValue - prevValue;
});
Таким образом, метод сортировки можно представить следующим образом:
function compareFunction(a, b) {
if (a is less than b by some ordering criterion) {
return -1;
}
if (a is greater than b by the ordering criterion) {
return 1;
}
a must be equal to b
return 0;
}
Надеемся, что это немного прояснит ситуацию с Array.sort()
.