В повседневной работе по программированию мы часто работаем со списками (массивами). Иногда мы хотим найти элементы, которые соответствуют определенному условию, для этого подходит метод Filter (), в других случаях мы можем захотеть преобразовать элементы данного массива на основе некоторой логики. , то мы можем применить метод Map (). А как насчет сценариев, когда мы хотим создать единое итоговое значение или сократить список элементов (массив) до единственного значения?

В этом руководстве мы узнаем, как использовать встроенный собственный метод JavaScript Reduce () для агрегирования результата или получения одного единственного значения. Это значение может быть строкой, числом, логическим значением или даже объектом и т. Д.

Во-первых, давайте попробуем решить следующую проблему, применив базовый ванильный JavaScript / подход for loop.

Вам дан массив чисел:

let arrayOfNumbers = [1, 2, 3, 4, 5, 6, 7];

Нам нужно сложить все элементы этого массива вместе, чтобы получить единое итоговое значение. Ожидаемый результат 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28.

Распространенный подход к решению подобных проблем заключается в том, что мы сначала объявляем новую переменную, в нашем случае это будет аккумулятор, и устанавливаем для него значение 0. Затем мы перебираем данный массив и добавляем текущий элемент к этой переменной аккумулятора. , с каждой следующей итерацией значение, которое мы храним в этой переменной-аккумуляторе, увеличивается на значение текущего элемента. Наконец, когда цикл завершен, мы возвращаем накопленное значение.

Ниже приведен псевдокод и сам код для этой проблемы. Попробуйте! Скопируйте и вставьте его в свою консоль.

function sum (numbers) {
// declare a new var and set it to 0
let accumulator = 0;
// iterate over an array
for (var i = 0; i < numbers.length; i++) {
// add the current element of the array to that new var till the end // of loop 
accumulator = accumulator + numbers[i];
    }
// return this accumulated value
return accumulator;
}
let arrayOfNumbers = [1, 2, 3, 4, 5, 6, 7];
let result = sum (arrayOfNumbers);
console.log(result);// output -> 28 

Вот результат в консоли:

Это очень простой способ вручную сложить все элементы массива, но, как вы можете видеть, он работает только в этой очень конкретной ситуации! Например, если я хочу добавить только первые N элементов или длина этого массива изменится, мне придется переписать свой код. В этом случае очень пригодится метод Reduce ()!

Как всегда, давайте посмотрим на официальное определение этого метода и синтаксиса в MDN Web Docs:

Метод Reduce () выполняет функцию сокращения (которую вы предоставляете) для каждого элемента массива, в результате чего получается одно выходное значение.

Функция reducer принимает четыре аргумента:

1. Аккумулятор

2. Текущая стоимость

3. Текущий индекс

4. Исходный массив

// Arrow function
reduce((accumulator, currentValue) => { ... } )
reduce((accumulator, currentValue, index) => { ... } )
reduce((accumulator, currentValue, index, array) => { ... } )
reduce((accumulator, currentValue, index, array) => { ... }, initialValue)
// Callback function
reduce(callbackFn)
reduce(callbackFn, initialValue)
// Inline callback function
reduce(function callbackFn(accumulator, currentValue) { ... })
reduce(function callbackFn(accumulator, currentValue, index) { ... })
reduce(function callbackFn(accumulator, currentValue, index, array){ ... })
reduce(function callbackFn(accumulator, currentValue, index, array) { ... }, initialValue)

Хорошо, вооружившись теоретическими знаниями о том, что делает метод Reduce (), давайте решим указанную выше проблему с помощью этого метода.

let arrayOfNumbers = [1, 2, 3, 4, 5, 6, 7];
let reducerFunction = (accumulator, currentValue) => accumulator + currentValue;
let result = arrayOfNumbers.reduce(reducerFunction)
console.log(result); // output -> 28; 

Приведенный выше код может показаться немного неудобным, поэтому давайте сделаем его короче и воспользуемся выражением стрелочной функции, как рекомендует официальная документация:

let arrayOfNumbers = [1, 2, 3, 4, 5, 6, 7];
let sum = arrayOfNumbers.reduce ((accumulator, currentValue) => accumulator + currentValue, 0);
console.log(sum); // output -> 28;

или используя встроенную функцию обратного вызова:

let arrayOfNumbers = [1, 2, 3, 4, 5, 6, 7];
let sum = arrayOfNumbers.reduce (function (accumulator, currentValue) {return accumulator + currentValue}, 0);
console.log(sum);// output -> 28;

Независимо от того, какой синтаксис вы выберете, результат будет одинаковым для всех стилей, указанных выше.

Что здесь происходит? Мы вызываем метод Reduce () в нашем источнике или входном массиве arrayOfNumbers и передаем ему два аргумента: функцию обратного вызова, определенную как выражение функции стрелки в данном случае (accumulator, currentValue) => accumulator + currentValue , и необязательное начальное значение или набор аккумуляторов. в 0 в этом случае. Затем метод выполняет функцию обратного вызова для каждого элемента исходного массива по очереди (1, 2, 3, 4… 7), каждый раз передавая текущее значение аккумулятора и текущий элемент. После каждой итерации функция обратного вызова обновляет значение аккумулятора аналогично тому, что мы видели ранее в этой строке кода accumulator = accumulator + numbers[i], и это обновленное значение аккумулятора затем передается в качестве первого аргумента функции обратного вызова и так до конца исходный массив. Когда во входном массиве нечего перебирать, окончательное значение аккумулятора возвращается так же, как return accumulator в примере, который я опубликовал в начале.

Начальное значение инициализации является необязательным, как указано в документации, но его отсутствие может привести к тому, чего вы на самом деле не ожидаете! Если начального начального значения нет, то первый элемент в массиве используется как начальное значение / начальное значение аккумулятора. Посмотрите следующие два примера:

Мы уже узнали, как применять и использовать метод Reduce () к примитивным типам, теперь давайте рассмотрим и продемонстрируем использование этого метода на объектах.

Предположим, что у нас есть команда супергероев (представленная в виде массива объектов), и нам нужно определить, например, какой герой самый быстрый. Для всех поклонников супергероев, я хочу заверить вас, что данные ниже действительны и взяты с этого сайта! Давайте выясним, кто быстрее всех - Железный человек, Черная вдова или Халк 🍾 🙌 🎉 !!!

let listOfHeroes = [
{
"Name":"Anthony Edward 'Tony' Stark",
"CurrentAlias":"Iron Man",
"Intelligence":6,
"Strength":6,
"Speed":5,
"Durability":6,
"EnergyProjection":6,
"FightSkills":4
},
{
"Name":"Natalia Alianovna 'Natasha' Romanova",
"CurrentAlias":"Black Widow",
"Intelligence":3,
"Strength":3,
"Speed":2,
"Durability":3,
"EnergyProjection":3,
"FightSkills":6
},
{
"Name":"Dr. Robert Bruce Banner",
"CurrentAlias":"Hulk",
"Intelligence":6,
"Strength":7,
"Speed":3,
"Durability":7,
"EnergyProjection":5,
"FightSkills":4
}]

Распространенный подход к определению наибольшего значения в любом массиве - это предположить, что одно значение, например, первое в данном массиве является наибольшим, затем выполнить итерацию по массиву, начиная со второго элемента, и сравнить каждый элемент с наибольшее значение по умолчанию. Если текущее значение больше максимального значения по умолчанию, выполните переназначение. Как только мы узнаем, какое наибольшее значение, мы можем запустить второй цикл for над исходным массивом, чтобы определить, какой индекс (или наш герой как объект) соответствует этому наибольшему значению, и затем вернуть объект-герой. Давайте решим эту проблему с помощью ванильного JavaScript и цикла for. Ниже приведен код и вывод:

function fastestHeroe(array) {
// assume the first element in this array is the largest one
let speedFast = array[0].Speed;
// iterate over the array starting from the second element and till the end of this array
for (var i = 1; i < array.length; i++) {
// if the current element is more than the assumed largest/first then assign this current element to speedFast var
if (array[i].Speed > speedFast) {
speedFast = array[i].Speed;
}}
// iterate over the array
for (var j = 0; j < array.length; j++) {
// if a value of “Speed” key is equal to the found largest one then return the current obj
if (array[j].Speed === speedFast) {
return array[j];
}}}

Если вы запустите этот код, он должен вернуть «Тони» Старка, потому что его значение «Скорость» равно 5, а это больше, чем у «Черной вдовы» и «Халка».

Теперь давайте продемонстрируем, как ту же проблему можно решить с помощью метода Reduce ():

var fastest = listOfHeroes.reduce(function (accumulator, hero) {return (accumulator.Speed || 0) > hero.Speed ? accumulator : hero;}, {});

Результат метода Reduce () такой же, как и после реализации подхода for loop.

Большой! Нам потребовалось всего несколько строк кода, чтобы уменьшить начальный массив объектов, чтобы определить, какой герой является самым быстрым по сравнению с несколькими строками кода и двумя циклами в подходе Vanilla JavaScript / for loop. .

Что касается победителя в этом соревновании метода Reduce () против for loop, то «Тони» Старк - самый быстрый супергерой, потому что его скорость равна 5, а она больше, чем у кого-то еще есть в этой сетке сверхспособностей. Поздравляю «Тони»! 💯

Подводя итог, можно сказать, что метод Reduce () используется, когда мы хотим получить некоторую информацию от каждого элемента во входном массиве и собрать эту информацию в итоговое итоговое значение сигнала (аккумулятор). Здесь нам нужно рассмотреть три основных аспекта: исходный массив или массив, который мы хотим уменьшить; функция обратного вызова или редуктор, определяющий, какие действия необходимо выполнить; начальное начальное значение для нашей переменной-аккумулятора. Функция Reduce () выполняет итерацию по исходному массиву, каждый раз вызывая функцию обратного вызова редуктора, которая, в свою очередь, возвращает обновленное значение аккумулятора.

Конечно, мы все еще можем сделать то же самое с помощью цикла for, как показано выше, но использование встроенной функции Reduce () освобождает нас от необходимости кодировать циклические механизмы, напишите несколько строк повторяющегося кода, объявляйте и накапливайте переменные в переменной типа аккумулятора, а затем возвращайте этот аккумулятор в конце.

Если вы найдете эту информацию полезной, подписывайтесь на меня. Надеюсь, вам понравилось это краткое руководство по методу Reduce () в JavaScript, будьте сильны и следите за обновлениями!