Возврат массивов и объектов из метода reduce()
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(). Спасибо за внимание.