Возврат массивов и объектов из метода reduce()

Источник: «Returning Arrays and Objects from the reduce() Method»
Приёмы, которые вы, вероятно, не знали о методе reduce()

На данный момент вы, скорее всего, уже знакомы с большинством методов работы с массивами, особенно с методами map(), filter() и reduce(). Однако вы, вероятно, не знали, что некоторые вещи, которые вы первоначально делали с помощью методов map() и filter(), можно также сделать с помощью метода reduce(). Мы можем возвращать из метода reduce() массивы и даже объекты, а также использовать его в качестве счётчика, в зависимости от того, для какой задачи он нужен. Не теряя времени, давайте рассмотрим некоторые из этих сценариев, в которых может пригодиться метод reduce().

Использование reduce() вместо filter()

Предположим, что нам дан массив ages, содержащий возрасты разных людей, и требуется составить массив из возрастов, которые попадают в возраст, необходимый для получения водительских прав (т.е. ages >= 18). Обычно это делается с помощью метода filter() следующим образом;

const ages = [14, 19, 16, 23, 12, 38, 20, 17, 10, 18];

const legalAge = ages.filter((el) => el >= 18);

console.log(legalAge); // Результат [19, 23, 38, 20, 18]

Результат функции legalAge возвращает массив возрастов, удовлетворяющих возрастному критерию, необходимому для получения водительских прав (возраст больше или равен 18 годам). Однако мы можем проделать то же самое, что и выше, используя метод reduce(), и получить тот же результат.

const ages = [14, 19, 16, 23, 12, 38, 20, 17, 10, 18];

const ageLegal = ages.reduce((acc, el) => {
if (el >= 18) acc.push(el);
return acc;
}, []);

console.log(ageLegal); // Результат [19, 23, 38, 20, 18]

Для этого нам потребуется функция, а также инициализация нашего аккумулятора (acc) в виде массива. Затем в методе reduce() мы зададим условие, помещающее текущий элемент итерации в массив аккумуляторов (acc) только в том случае, если он больше или равен "18", а также явно вернём наш аккумулятор (поскольку в теле функции аккумулятор не возвращается автоматически).

Использование reduce() вместо map()

Предположим, что нам дан массив значений, затем нужно разделить значения этого массива на два и сохранить результат в новом массиве, мы можем сделать это с помощью метода map() таким образом;

const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];

const arrHalf = arr.map((el) => el / 2);

console.log(arrHalf);
// Результат [0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5]

В качестве альтернативы можно также использовать метод reduce() для решения задачи следующим образом;

const halfRed = arr.reduce((acc, el) => {
acc.push(el / 2);
return acc;
}, []);

console.log(halfRed);
// Результат [0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5]

Мы инициализируем аккумулятор как пустой массив, а затем на каждой итерации помещаем в массив текущий элемент, делённый на два, аккумулятор также явно возвращается.

Возврат объекта из метода reduce()

Предположим, что нам дан массив, содержащий набор транзакций (снятия и пополнения), и мы должны на основе этого массива создать объект, содержащий свойства deposit и withdraw. Как это сделать с помощью метода reduce();

const transactions = [-100, 200, 350, -400, -10, 30, -8, 120, 20];

const transactionObj = transactions.reduce(
(acc, el) => {
el < 0 ? (acc.withdrawals += el) : (acc.deposits += el);
return acc;
},
{ deposits: 0, withdrawals: 0 }
);

console.log(transactionObj);
// Результат {deposits: 720, withdrawals: -518}

Наш аккумулятор инициализируется как объект, содержащий свойства deposit и withdrawals, причём оба они имеют начальные значения, равные нулю. Затем на каждой итерации, используя тернарный оператор, мы добавляем текущее значение массива к свойствам deposit или withdrawals в зависимости от того, больше оно (т.е. текущее значение) нуля или нет. Наконец, мы также явно возвращаем наш объект аккумулятор.

Подсчёт с помощью метода reduce()

Если предположить, что нам нужно подсчитать количество депозитов в массиве transactions (т.е. Транзакции больше нуля), то, не задумываясь, мы можем использовать метод filter() для фильтрации значений больше нуля и просто взять длину возвращаемого массива, как показано ниже;

const transactions = [-100, 200, 350, -400, -10, 30, -8, 120, 20];

const numDeposits = transactions.filter((el) => el > 0).length;

console.log(numDeposits); // Результат 5

Как видно из вышеприведённого, numDeposits возвращает значение 5, которое является результатом количества депозитов в массиве transactions. В качестве альтернативы можно использовать метод reduce(), например, так;

const transactions = [-100, 200, 350, -400, -10, 30, -8, 120, 20];

const depositsNum = transactions.reduce((acc, el) => (el > 0 ? ++acc : acc)
, 0);
console.log(depositsNum); // Результат 5

В приведённом выше методе аккумулятор инициализируется равным 0, а затем на каждой итерации с помощью тернарного оператора мы добавляем в аккумулятор единицу, если текущий элемент больше нуля, и возвращаем аккумулятор с предыдущей итерации, если текущий элемент меньше нуля. Обратите внимание, что вместо acc++ мы использовали ++acc, так как прямое возвращение acc++ не даёт желаемого результата, поскольку в каждой итерации будет возвращаться 0.

Заключение

Данная статья ни в коем случае не ставит своей целью убедить читателя отказаться от традиционных методов выполнения операций над массивами, к которым он уже привык. Напротив, она призвана показать читателям другие удобные способы выполнения операций над массивами в JavaScript с помощью метода reduce(), а также продемонстрировать несколько расширенных (нетрадиционных) функциональных возможностей, которые могут быть реализованы с помощью метода reduce(). Спасибо за внимание.

Дополнительные материалы

Предыдущая Статья

Совет по безопасности: Защитите свой файл .env

Следующая Статья

Демистификация git cherry-pick: обзор команды с примерами