En guide til reduktion af metoden i Javascript

JavaScript's reduceringsmetode er en af ​​hjørnestenene i funktionel programmering.Lad os undersøge, hvordan det fungerer, hvornår du skal bruge det, og nogle af de seje ting, det kan gøre.

En grundlæggende reduktion

Brug det når : Du har en række beløb, og du vil tilføje dem alle sammen.

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

Brugsvejledning:

  • I dette eksempel accepterer Reduce to parametre, det samlede og det aktuelle beløb.
  • Metoden reducere cykler gennem hvert nummer i arrayet, ligesom det ville være i en for-loop.
  • Når sløjfen starter, er den samlede værdi tallet længst til venstre (29,76), og det aktuelle beløb er det næste ved siden af ​​(41,85).
  • I dette særlige eksempel ønsker vi at tilføje det aktuelle beløb til det samlede beløb.
  • Beregningen gentages for hvert beløb i arrayet, men hver gang den aktuelle værdi skifter til det næste tal i arrayet, og bevæger sig til højre.
  • Når der ikke er flere tal tilbage i matrixen, returnerer metoden den samlede værdi.

ES5-versionen af ​​Reducer-metoden i JavaScript

Hvis du aldrig har brugt ES6-syntaks før, skal du ikke lade eksemplet ovenfor skræmme dig. Det er nøjagtigt det samme som at skrive:

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

Vi bruger i conststedet for, varog vi erstatter ordet functionmed en “fed pil” ( =>) efter parametrene, og vi udelader ordet 'return'.

Jeg bruger ES6-syntaks i resten af ​​eksemplerne, da det er mere kortfattet og giver mindre plads til fejl.

Find et gennemsnit med reduceringsmetoden i JavaScript

I stedet for at logge summen kan du dele summen med længden af ​​arrayet, før du returnerer en endelig værdi.

Måden at gøre dette på er ved at udnytte de andre argumenter i reduceringsmetoden. Det første af disse argumenter er indekset . Ligesom en for-loop refererer indekset til det antal gange, reduceringsenheden har loopet over arrayet. Det sidste argument er selve arrayet .

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

Kort og filtrer som reduktioner

Hvis du kan bruge reduceringsfunktionen til at spytte et gennemsnit, kan du bruge det som du vil.

For eksempel kan du fordoble den samlede, eller halvdelen hvert nummer, før du tilføjer dem sammen, eller brug en if-sætning inde i reducering til kun tilføje tal, som er større end 10. Min pointe er, at reducere Metode I JavaScript giver dig en mini CodePen hvor du kan skrive hvilken logik du vil have. Det gentager logikken for hvert beløb i arrayet og returnerer derefter en enkelt værdi.

Sagen er, at du ikke altid skal returnere en enkelt værdi. Du kan reducere en matrix til en ny matrix.

Lad os f.eks. Reducere en matrix af beløb til en anden matrix, hvor hvert beløb fordobles. For at gøre dette skal vi indstille den oprindelige værdi for vores akkumulator til et tomt array.

Den oprindelige værdi er værdien af ​​den samlede parameter, når reduktionen starter. Du indstiller startværdien ved at tilføje et komma efterfulgt af din oprindelige værdi inden for parenteserne, men efter de krøllede parenteser ( fed i eksemplet nedenfor ).

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

I tidligere eksempler var den oprindelige værdi nul, så jeg udeladte den. Ved at udelade den oprindelige værdi, vil summen som standard være det første beløb i arrayet.

Ved at indstille startværdien til et tomt array kan vi derefter skubbe hvert beløb ind i det samlede beløb . Hvis vi vil reducere en række værdier til en anden matrix, hvor hver værdi fordobles, er vi nødt til at skubbe beløbet * 2. Så returnerer vi det samlede antal, når der ikke er flere beløb at skubbe.

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]

Vi har oprettet et nyt array, hvor hvert beløb fordobles. Vi kunne også filtrere numre, som vi ikke ønsker at fordoble, ved at tilføje en if-sætning inde i vores reducer.

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 ]

Disse operationer er kort- og filtermetoderne omskrevet som en reduceringsmetode.

For disse eksempler ville det være mere fornuftigt at bruge kort eller filter, fordi de er enklere at bruge. Fordelen ved at bruge reducere kommer i spil, når du vil kortlægge og filtrere sammen, og du har en masse data at gå over.

Hvis du kæder kort og filtrerer sammen, udfører du arbejdet to gange. Du filtrerer hver enkelt værdi og kortlægger derefter de resterende værdier. Med reducer kan du filtrere og derefter kortlægge i et enkelt pass.

Brug kort og filter, men når du begynder at kæde mange metoder sammen, ved du nu, at det er hurtigere at reducere dataene i stedet.

Creating a Tally with the Reduce Method In JavaScript​

Use it when: You have a collection of items and you want to know how many of each item are in the collection.

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 }

To tally items in an array our initial value must be an empty object, not an empty array like it was in the last example.

Since we are going to be returning an object we can now store key-value pairs in the total.

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

On our first pass, we want the name of the first key to be our current value and we want to give it a value of 1.

This gives us an object with all the fruit as keys, each with a value of 1. We want the amount of each fruit to increase if they repeat.

To do this, on our second loop we check if our total contain a key with the current fruit of the reducer. If it doesn’t then we create it. If it does then we increment the amount by one.

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.

Tak for læsningen! Hvis du gerne vil have besked, når jeg skriver en ny artikel, skal du indtaste din e-mail her.

Og hvis du kunne lide artiklen, så del den på sociale medier, så andre kan finde den.