Ръководство за метода за намаляване в Javascript

Методът за намаляване на JavaScript е един от крайъгълните камъни на функционалното програмиране.Нека да проучим как работи, кога трябва да го използвате и някои от страхотните неща, които може да направи.

Основно намаление

Използвайте го, когато : Имате масив от суми и искате да ги съберете всички.

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

Как се използва:

  • В този пример, Намаляване приема два параметъра, общата и текущата сума.
  • Методът за редуциране циклизира всяко число в масива, подобно на това в for-loop.
  • Когато цикълът започне, общата стойност е числото вляво (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.