Посібник із методу зменшення в Javascript

Метод зменшення JavaScript є одним з наріжних каменів функціонального програмування.Давайте вивчимо, як це працює, коли вам слід ним користуватися, та деякі цікаві речі, які він може зробити.

Основне зменшення

Використовуйте його, коли : У вас є масив сум, і ви хочете скласти їх усі.

const euros = [29.76, 41.85, 46.5]; const sum = euros.reduce((total, amount) => total + amount); sum // 118.11

Як користуватися ним:

  • У цьому прикладі Reduce приймає два параметри - загальну та поточну суму.
  • Метод зменшення проходить через кожне число в масиві так само, як у циклі for.
  • Коли цикл починається, загальне значення - це число вкрай ліворуч (29,76), а поточна сума - це поряд з ним (41,85).
  • У цьому конкретному прикладі ми хочемо додати поточну суму до загальної суми.
  • Обчислення повторюється для кожної суми в масиві, але кожного разу, коли поточне значення змінюється на наступне число в масиві, рухаючись праворуч.
  • Коли в масиві не залишається більше чисел, метод повертає загальне значення.

Версія ES5 методу зменшення в JavaScript

Якщо ви ніколи раніше не використовували синтаксис ES6, не дозволяйте наведеному вище прикладу вас залякувати. Це точно те саме, що писати:

var euros = [29.76, 41.85, 46.5]; var sum = euros.reduce( function(total, amount){ return total + amount }); sum // 118.11

Ми використовуємо constзамість varі замінюємо слово functionна “жирну стрілку” ( =>) після параметрів, а слово “return” опускаємо.

Я буду використовувати синтаксис ES6 для решти прикладів, оскільки він є більш стислим і залишає менше місця для помилок.

Пошук середнього за допомогою методу зменшення в JavaScript

Замість реєстрації суми, ви можете розділити суму на довжину масиву, перш ніж повернути остаточне значення.

Це можна зробити, скориставшись іншими аргументами методу зменшення. Першим із цих аргументів є індекс . Так само, як for-loop, індекс відноситься до того, скільки разів редуктор прокручував масив. Останній аргумент - це сам масив .

const euros = [29.76, 41.85, 46.5]; const average = euros.reduce((total, amount, index, array) => { total += amount; if( index === array.length-1) { return total/array.length; }else { return total; } }); average // 39.37

Карта та фільтр як зменшення

Якщо ви можете використовувати функцію зменшення, щоб виплюнути середнє значення, тоді ви можете використовувати її як завгодно.

Наприклад, ви можете подвоїти суму, або половину кожного номера , перш ніж додавати їх разом, або якщо заяву використовувати всередині редуктора тільки додати номери, які більше , ніж 10. Моя точка є те , що метод скорочення У JavaScript дає міні CodePen, де ви можете писати будь-яку логіку, яку хочете. Він повторить логіку для кожної суми в масиві, а потім поверне одне значення.

Справа в тому, що вам не завжди потрібно повертати одне значення. Ви можете зменшити масив до нового масиву.

Наприклад, дозволяє зменшити масив сум в інший масив, де кожна сума подвоюється. Для цього нам потрібно встановити початкове значення для нашого акумулятора порожнім масивом.

Початкове значення - це значення загального параметра, коли починається зменшення. Ви встановлюєте початкове значення, додаючи кому, за якою йде початкове значення всередині дужок, але після фігурних дужок ( виділено жирним шрифтом у прикладі нижче ).

const average = euros.reduce((total, amount, index, array) => { total += amount return total/array.length }, 0);

У попередніх прикладах початкове значення було нульовим, тому я його опустив. Якщо опустити початкове значення, загальна сума за замовчуванням буде першою сумою в масиві.

Встановивши для початкового значення порожній масив, ми можемо потім перенести кожну суму в загальну суму . Якщо ми хочемо зменшити масив значень в інший масив, де кожне значення подвоюється, нам потрібно просунути суму * 2. Тоді ми повертаємо загальну суму, коли більше немає суми для надсилання.

const euros = [29.76, 41.85, 46.5]; const doubled = euros.reduce((total, amount) => { total.push(amount * 2); return total; }, []); doubled // [59.52, 83.7, 93]

Ми створили новий масив, де кожна сума подвоюється. Ми також можемо відфільтрувати числа, які ми не хочемо подвоювати, додавши оператор if всередину нашого редуктора.

const euro = [29.76, 41.85, 46.5]; const above30 = euro.reduce((total, amount) => { if (amount > 30) { total.push(amount); } return total; }, []); above30 // [ 41.85, 46.5 ]

Ці операції є методами карти та фільтра, переписаними як метод зменшення.

Для цих прикладів має сенс використовувати карту чи фільтр, оскільки вони простіші у використанні. Перевага використання функції зменшення набуває значення, коли ви хочете зіставити та відфільтрувати разом, і у вас є багато даних для перегляду.

Якщо ви об’єднали карту і фільтруєте разом, ви робите роботу двічі. Ви фільтруєте кожне окреме значення, а потім зіставляєте інші значення. З функцією зменшення можна фільтрувати, а потім складати карту за один прохід.

Використовуйте карту та фільтр, але коли ви починаєте поєднувати безліч методів разом, тепер ви знаєте, що швидше зменшити дані замість цього.

Створення підрахунку за методом зменшення в JavaScript

Використовуйте його, коли : У вас є колекція предметів, і ви хочете знати, скільки кожного елемента є в колекції.

const fruitBasket = ['banana', 'cherry', 'orange', 'apple', 'cherry', 'orange', 'apple', 'banana', 'cherry', 'orange', 'fig' ]; const count = fruitBasket.reduce( (tally, fruit) =>  , {}) count // { banana: 2, cherry: 3, orange: 3, apple: 2, fig: 1 }

Для підрахунку елементів у масиві нашим початковим значенням повинен бути порожній об'єкт, а не порожній масив, як це було в останньому прикладі.

Оскільки ми збираємось повертати об'єкт, тепер ми можемо зберігати пари ключ-значення у загальній сумі.

fruitBasket.reduce( (tally, fruit) => { tally[fruit] = 1; return tally; }, {})

Під час першого проходження ми хочемо, щоб ім’я першого ключа було нашим поточним значенням, і ми хочемо надати йому значення 1.

Це дає нам об’єкт із усіма фруктами в якості ключів, кожен із значенням 1. Ми хочемо, щоб кількість кожного фрукта збільшувалася, якщо вони повторюються.

Для цього у нашому другому циклі ми перевіряємо, чи містить наш підсумок ключ із поточним результатом редуктора. Якщо цього не сталося, ми його створюємо. Якщо це так, ми збільшуємо суму на одиницю.

fruitBasket.reduce((tally, fruit) => { if (!tally[fruit]) { tally[fruit] = 1; } else { tally[fruit] = tally[fruit] + 1; } return tally; }, {});

I rewrote the exact same logic in a more concise way up top.

Flattening an array of arrays with the Reduce Method In JavaScript​​

We can use reduce to flatten nested amounts into a single array.

We set the initial value to an empty array and then concatenate the current value to the total.

const data = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]; const flat = data.reduce((total, amount) => { return total.concat(amount); }, []); flat // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

More often than not, information is nested in more complicated ways. For instance, lets say we just want all the colors in the data variable below.

const data = [ {a: 'happy', b: 'robin', c: ['blue','green']}, {a: 'tired', b: 'panther', c: ['green','black','orange','blue']}, {a: 'sad', b: 'goldfish', c: ['green','red']} ];

We’re going to step through each object and pull out the colours. We do this by pointing amount.c for each object in the array. We then use a forEach loop to push every value in the nested array into out total.

const colors = data.reduce((total, amount) => { amount.c.forEach( color => { total.push(color); }) return total; }, []) colors //['blue','green','green','black','orange','blue','green','red']

If we only need unique number then we can check to see of the number already exists in total before we push it.

const uniqueColors = data.reduce((total, amount) => { amount.c.forEach( color => { if (total.indexOf(color) === -1){ total.push(color); } }); return total; }, []); uniqueColors // [ 'blue', 'red', 'green', 'black', 'orange']

Piping with Reduce

An interesting aspect of the reduce method in JavaScript is that you can reduce over functions as well as numbers and strings.

Let’s say we have a collection of simple mathematical functions. these functions allow us to increment, decrement, double and halve an amount.

function increment(input) { return input + 1;} function decrement(input) { return input — 1; } function double(input) { return input * 2; } function halve(input) { return input / 2; }

For whatever reason, we need to increment, then double, then decrement an amount.

You could write a function that takes an input, and returns (input + 1) * 2 -1. The problem is that we know we are going to need to increment the amount three times, then double it, then decrement it, and then halve it at some point in the future. We don’t want to have to rewrite our function every time so we going to use reduce to create a pipeline.

A pipeline is a term used for a list of functions that transform some initial value into a final value. Our pipeline will consist of our three functions in the order that we want to use them.

let pipeline = [increment, double, decrement];

Instead of reducing an array of values we reduce over our pipeline of functions. This works because we set the initial value as the amount we want to transform.

const result = pipeline.reduce(function(total, func) { return func(total); }, 1); result // 3

Because the pipeline is an array, it can be easily modified. If we want to decrement something three times, then double it, decrement it , and halve it then we just alter the pipeline.

var pipeline = [ increment, increment, increment, double, decrement, halve ];

The reduce function stays exactly the same.

Silly Mistakes to avoid

If you don’t pass in an initial value, reduce will assume the first item in your array is your initial value. This worked fine in the first few examples because we were adding up a list of numbers.

If you’re trying to tally up fruit, and you leave out the initial value then things get weird. Not entering an initial value is an easy mistake to make and one of the first things you should check when debugging.

Another common mistake is to forget to return the total. You must return something for the reduce function to work. Always double check and make sure that you’re actually returning the value you want.

Tools, Tips & References

  • Everything in this post came from a fantastic video series on egghead called Introducing Reduce. I give Mykola Bilokonsky full credit and I am grateful to him for everything I now know about using the Reduce Method In JavaScript​. I have tried to rewrite much of what he explains in my own words as an exercise to better understand each concept. Also, it’s easier for me to reference an article, as opposed to a video, when I need to remember how to do something.
  • The MDN Reduce documentation labels what I called a total the accumulator. It is important to know this because most people will refer to it as an accumulator if you read about it online. Some people call it prev as in previous value. It all refers to the same thing. I found it easier to think of a total when I was learning reduce.
  • If you would like to practice using reduce I recommend signing up to freeCodeCamp and completing as many of the intermediate algorithms as you can using reduce.
  • If the ‘const’ variables in the example snippets are new to you I wrote another article about ES6 variables and why you might want to use them.
  • I also wrote an article called The Trouble With Loops that explain how to use map() and filter() if the are new to you.

Thanks for reading! If you’d like to be notified when I write a new article please enter your email here.

And if you liked the article, please share it on social media so others can find it.