February 12, 2020

Методы массивов: map, sort

Метод map

Метод map создает новый массив из элементов, которые будут являться результатами выполнения callback-функции.

У метода map имеется только один аргумент, который является callback-функцией. У этой функции имеется 3 аргумента, по аналогии с методами описанными выше:

Первый аргумент – текущей элемент (элемент на текущей итерации).

Второй аргумент – индекс этого элемента в массиве.

Третий аргумент – сам массив.

Повторюсь, callback-функция может быть как обычной (function declaration), так и стрелочной (arrow function).

Пример использования:

const numbers = [2, 5, 7, 9];
const results = numbers.map(n => n ** 5);

results; //[32, 3125, 16807, 59049]

Из исходного массива numbers, с помощью метода map мы создали новый массив, в котором каждое число было возведено в 5-ую степень.

Метод sort

Метод sort, как несложно догадаться по названию – сортирует массив. При этом, сортирует он его "на месте", что означает, что изменяется исходный массив. Плюсом к этому этот метод еще и возвращает тот же самый массив, т.е. результат выполнения данного метода можно еще и в другую переменную запихнуть (но это делается крайне редко).

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

const characters = ['d', 'z', 'a', 'c', 'y'];
characters.sort();

characters; //['a', 'c', 'd', 'y', 'z']

Как видишь, метод расположил буквы в соответствии с правильными их расположением в латинском алфавите. Но что же будет, если применить метод sort к массиву с числами? Глянем:

const numbers = [45, 4, 2, 1, -50, 300, 0];
numbers.sort();

numbers; //[-50, 0, 1, 2, 300, 4, 45]

И казалось бы, что может пойти не так.... Но, всмотрись внимательно и увидишь, что значение 300 заняло далеко не свое место в этом танце =) Почему так? Потомукта. А если серьезно, то случилось это по той причине, что метод sort по умолчанию при работе с элементами массива преобразует их (элементы) к строковому типу и для сортировки применяется лексикографический порядок. А если сравнивать строки, то строка 300 будет больше чем строка 4. Чтобы такой чепухи не было, нам нужно задать свой порядок сортировки, со своим Блэкджеком и шлюпками.

Ты же заметил, что мы не передавали никакого аргумента в метод sort, а они у него есть. И да, это снова callback-функция. Если ты ее передашь, то она и будет (должна) задавать правила сортировки для массива.

Главное правило callback-функции для данного метода – для пары значений она должна возвращать:

  • 1 (или любое положительное число) – если первое значение больше второго;
  • 0 – если значения равны;
  • -1 (или любое отрицательное число) – если первое значение меньше второго.

Теперь подкрепим понимание кодом:

const numbers = [45, 4, 2, 1, -50, 300, 0];

function compare(a, b) {
   if (a > b) return 1;
   if (a === b) return 0;
   if (a < b) return - 1;
};

numbers.sort(compare);

numbers; //[-50, 0, 1, 2, 4, 45, 300]

Вот оно, чудо из всех чудес! Теперь сортировка отработала совершенно правильно.

Что же мы поменяли? Да в целом, ничего. Мы создали функцию, в которой описали при каких условиях и что возвращать используя правило выше. И эту функцию мы передали в аргумент метода. И все заработало как часы.

Конкретно данный случай можно еще и упростить, если использовать стрелочную функцию и немного включить логику. Смотри:

const numbers = [45, 4, 2, 1, -50, 300, 0];

numbers.sort((a, b) => a - b);

numbers; //[-50, 0, 1, 2, 4, 45, 300]

Воу!!! Код колосально сократился, но чего же мы такого тут поменяли?

Во-первых, мы ввели стрелочную функцию, что в львиной доле случаев делает код короче автоматически.

Во-вторых, посмотри на эту функцию: (a, b) => a - b. Здесь так же фигурируют a и b, как и в примере выше и мы возвращаем их разницу. Зачем?

Ты не забыл о главном правиле? Функция должна вернуть 1(или любое положительное число), 0 или -1(или любое отрицательное число).

Именно это тут и вернется. Если числа будут равны, то результат a - b даст нам значение 0. Если a > b, то нам вернется положительное число, если a < b, то вернутся отрицательное число. Таким образом правило у нас исполняется и метод работает как нужно.