What is javascript reduce

.reduce ( )

Швейцарский нож для работы с массивами. Заменяет все остальные методы (не повторяйте дома).

Обновлено 13 февраля 2023

Кратко

Скопировать ссылку «Кратко» Скопировано

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

Пример

Скопировать ссылку «Пример» Скопировано

 const nums = [1, 2, 3, 4, 5, 6, 7, 8] const sum = nums.reduce(function (currentSum, currentNumber)  return currentSum + currentNumber>, 0)// 36 const nums = [1, 2, 3, 4, 5, 6, 7, 8] const sum = nums.reduce(function (currentSum, currentNumber)  return currentSum + currentNumber >, 0) // 36      

Создаём новый объект с ID и именем юзера:

 const users = [ < id: "1", name: "John" >, < id: "2", name: "Anna" >, < id: "3", name: "Kate" >,] const usernamesById = users.reduce(function (result, user)  return  . result, [user.id]: user.name, >>, <>)// const users = [  id: "1", name: "John" >,  id: "2", name: "Anna" >,  id: "3", name: "Kate" >, ] const usernamesById = users.reduce(function (result, user)  return  . result, [user.id]: user.name, > >, >) //     

Как пишется

Скопировать ссылку «Как пишется» Скопировано

Метод reduce ( ) принимает два параметра: функцию-колбэк и начальное значение для аккумулятора.

Сама функция-колбэк может принимать четыре параметра:

  • acc — текущее значение аккумулятора;
  • item — элемент массива в текущей итерации;
  • index — индекс текущего элемента;
  • arr — сам массив, который мы перебираем.
 const nums = [1, 2, 3, 4, 5, 6, 7, 8] // Не забываем, что аккумулятор идет первым!function findAverage(acc, item, index, arr)  const sum = acc + item // Если мы на последнем элементе // вычисляем среднее арифметическое делением на кол-во элементов: if (index === arr.length - 1)  return sum / arr.length > return sum> const average = nums.reduce(findAverage, 0)// 4.5 const nums = [1, 2, 3, 4, 5, 6, 7, 8] // Не забываем, что аккумулятор идет первым! function findAverage(acc, item, index, arr)  const sum = acc + item // Если мы на последнем элементе // вычисляем среднее арифметическое делением на кол-во элементов: if (index === arr.length - 1)  return sum / arr.length > return sum > const average = nums.reduce(findAverage, 0) // 4.5      

Функция обязательно должна возвращать значение, поскольку в каждой следующей итерации значение в acc будет результатом, который вернулся на предыдущем шаге. Логичный вопрос, который может здесь возникнуть — какое значение принимает acc во время первой итерации? Им будет то самое начальное значение, которое передаётся вторым аргументом в метод reduce ( ) .

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

 const arr = [1, 2, 3]const sum = arr.reduce(function (acc, val)  return acc + val>)console.log(sum)// 6 const arr = [1, 2, 3] const sum = arr.reduce(function (acc, val)  return acc + val >) console.log(sum) // 6      

Во фрагменте выше acc на первой итерации равен 1, а val — 2. Затем к полученному аккумулированному значению 3 прибавляется 3, и возвращается результат.

В этом подходе есть краевой случай. Если массив окажется пустым и начальное значение не будет указано, то JavaScript выдаст ошибку TypeError : Reduce of empty array with no initial value . Этот случай нужно обрабатывать отдельно, например, обернув reduce ( ) в try . . . catch , но лучше всегда указывать начальное значение.

Как понять

Скопировать ссылку «Как понять» Скопировано

Использование reduce ( ) похоже на методы for Each , map и filter — в них тоже передаётся функция-колбэк. Однако в reduce ( ) есть дополнительный аргумент — это текущее аккумулируемое значение. При этом можно заметить, что порядок аргументов тоже немного изменён.

Главной особенностью reduce ( ) , которую важно запомнить, является наличие аккумулятора. Аккумулятор — это и есть то новое вычисляемое значение. Во время выполнения функции-колбэка нужно обязательно возвращать его значение, поскольку оно попадает в следующую итерацию, где будет использоваться для дальнейших вычислений. Мы можем представить аккумулятор как переменную, значение которой можно поменять в каждой новой итерации. С помощью второго аргумента в reduce ( ) эта переменная получает своё начальное значение.

Метод reduce ( ) крайне полезен, когда мы хотим с помощью манипуляции значениями массива вычислить какое-то новое значение. Такую операцию называют агрегацией. Это мощный инструмент для обработки данных: например, его можно использовать для нахождения суммы величин в массиве или группировки в другие типы данных.

Задача: вычислить сумму денег на всех счетах.

 const bankAccounts = [ < id: "123", amount: 19 >, < id: "345", amount: 33 >, < id: "567", amount: 4 >, < id: "789", amount: 20 >,] const totalAmount = bankAccounts.reduce( // Аргумент sum является аккумулятором, // в нём храним промежуточное значение function (sum, currentAccount)  // Каждую итерацию берём текущее значение // и складываем его с количеством денег // на текущем счету return sum + currentAccount.amount >, 0 // Начальное значение аккумулятора) console.log(totalAmount)// 76 const bankAccounts = [  id: "123", amount: 19 >,  id: "345", amount: 33 >,  id: "567", amount: 4 >,  id: "789", amount: 20 >, ] const totalAmount = bankAccounts.reduce( // Аргумент sum является аккумулятором, // в нём храним промежуточное значение function (sum, currentAccount)  // Каждую итерацию берём текущее значение // и складываем его с количеством денег // на текущем счету return sum + currentAccount.amount >, 0 // Начальное значение аккумулятора ) console.log(totalAmount) // 76      

Чтобы понять, как это работает, можно взглянуть на код, который делает то же самое, но уже без reduce ( ) :

 const bankAccounts = [ < id: "123", amount: 19 >, < id: "345", amount: 33 >, < id: "567", amount: 4 >, < id: "789", amount: 20 >,] const bankAccounts = [  id: "123", amount: 19 >,  id: "345", amount: 33 >,  id: "567", amount: 4 >,  id: "789", amount: 20 >, ]      

Определяем, где будем хранить сумму, это в нашем случае является аккумулятором. Здесь же определяем начальное значение аккумулятора:

 let totalAmount = 0 for (let i = 0; i < bankAccounts.length; i++)  const currentAccount = bankAccounts[i] // В каждой итерации прибавляем // к текущей сумме количество денег на счету totalAmount += currentAccount.amount> console.log(totalAmount)// 76 let totalAmount = 0 for (let i = 0; i  bankAccounts.length; i++)  const currentAccount = bankAccounts[i] // В каждой итерации прибавляем // к текущей сумме количество денег на счету totalAmount += currentAccount.amount > console.log(totalAmount) // 76      

И в том, и в том другом примере у нас аккумулятор, где хранится текущее значение и кладётся новое, есть вычисление нового значение. Только reduce ( ) позволяет сделать это в одном месте и в более понятном декларативном стиле.

Подсказки

Скопировать ссылку «Подсказки» Скопировано

💡 Ключ к успешному использованию reduce ( ) — внимательно следить за порядком аргументов и не забывать возвращать значение.

На практике

Скопировать ссылку «На практике» Скопировано

Источник

How the JavaScript reduce and reduceRight Methods Work

Ashutosh Biswas

Ashutosh Biswas

How the JavaScript reduce and reduceRight Methods Work

reduce and reduceRight are two built-in JavaScript array methods that have a bit of a steep learning curve.

But the very essence of these methods are as simple as the following arithmetic computations.

Suppose we have an array of numbers:

And we want to get the sum of them.

The reduce way to get the sum is similar to:

Whereas the reduceRight way to get the sum is similar to:

With reduce and reduceRight , you can define your own +. Array elements can be anything too. Sounds exciting, right?

Think of reduce and reduceRight as nothing but a generalization of the above arithmetic patterns. In this article we will cover all the important details.

This article takes an easy-to-digest algorithmic approach to show you how reducing works in JavaScript.

I’ve also created a video to show you how these methods work. Check it out if want to learn the concepts from a more visual angle:

reduce-diagram1-1

  • acc is used to access previousValue .
  • curVal is used to access currentElement .
  • The circular shaped input to r represents curVal .
  • The rectangular shaped input to r represents acc or the accumulator.
  • Initial values are in rectangular shapes, because they are received by r as acc s.

4 The algorithm of reduce / reduceRight §

The 29 line algorithm below might look intimidating at first glance. But you’ll likely find it much easier to understand it than digesting globs of long sentences explaining the intricate details of these methods.

Note: The algorithm described here has the context of the «Parameters of reduce/reduceRight» section. (That is, the variables myArray , callbackfn and initialValue come from that section.)

So relax, enjoy the steps, and don’t forget to experiment in the console:

Note: An array can have a length greater than 0 but no elements. Such empty places in the array are usually called holes in the array. For example:

let arr = [. ]; console.log(arr.length); // 4 // note that trailing comma doesn't increase the length. // This feature enables us to add a new element quickly. 

These methods only call callbackfn for elements of myArray which actually exist. For example if you have an array like [1,,3,,5] , they will not consider the non-existing elements at indices 1 and 3 . Try to guess what will be logged after running the following:

If you said 6 , you are right!

⚠️ Warning: It is not recommended to modify myArray inside of callbackfn because it complicates the logic of your code and thus increases the possibility of bugs.

If you’ve read and understood this far, congratulations! Now you should have a solid understanding of how reduce / reduceRight works.

It’s a great time to solve some problems to get used to reduce / reduceRight . Before seeing the solutions, solve them yourself or at least spend some time thinking about it.

5 Excercises §

5.1 Flat nested array §

Write a function flatten that can flat a nested array.

let arr = [1, [2, [3], [[4], 5], 6]]; console.log(flatten(arr)); // [1, 2, 3, 4, 5, 6] 
 const flatten = (arr) => arr.reduce((acc, curVal) => acc.concat(Array.isArray(curVal) ? flatten(curVal) : curVal), []); 

5.2 Remove duplicate items from an array §

Write a function rmDuplicates that removes the duplicate items like below:

console.log(rmDuplicates([1, 2, 2, 3, 4, 4, 4])); // [1, 2, 3, 4]
 const rmDuplicates = arr => arr.reduce((p, c) => p.includes(c) ? p : p.concat(c), []); 

5.3 Reverse an array without mutating it §

There is a built-in reverse array method to reverse arrays. But it mutates the original array. Use reduceRight to reverse an array without mutating it.

 let arr = [1, 2, 3]; let reversedArr = arr.reduceRight((acc, curVal) => [. acc, curVal], []); console.log(arr); // [1, 2, 3] console.log(reversedArr); // [3, 2, 1] 

Note that by reversing array this way you will lose all the holes in the array.

6 Conclusion §

When reduce / reduceRight calls callbackfn internally we can call those patterns of calling it «normal behaviors» and we can treat other scenarios as edge cases. These can be summarized in the table below:

Initial value Number of elements Output
Present 0 Edge case: Initial value
Present Greater than 0 Normal behavior
Absent 0 Edge case: TypeError
Absent 1 Edge case: That element
Absent Greater than 1 Normal behavior

Learning reduce / reduceRight is a little bit more involved than other higher order array methods. But it’s worth your time to learn it well.

Thank you for reading! I hope this article was helpful. If you want you can checkout my website and follow me on Twitter and LinkedIn.

Источник

Читайте также:  Css inline border radius
Оцените статью