
A JavaScript csökkentési módszere a funkcionális programozás egyik alappillére.Fedezzük fel, hogyan működik, mikor kell használni, és néhány jó dolgot, amit tehet.
Alapvető csökkentés
Használja, ha : Van egy sor tömbje, és szeretné mindet összeadni.
const euros = [29.76, 41.85, 46.5]; const sum = euros.reduce((total, amount) => total + amount); sum // 118.11
Hogyan kell használni:
- Ebben a példában a Reduce két paramétert fogad el, a teljes és az aktuális összeget.
- A redukciós módszer a tömb minden egyes számát úgy ciklusolja, mint egy for-ciklus esetén.
- Amikor a hurok elkezdődik, a teljes érték a bal szélső szám (29,76), a jelenlegi pedig a mellette lévő (41,85).
- Ebben a konkrét példában hozzá akarjuk adni az aktuális összeget az összeghez.
- A számítást megismételjük a tömb minden egyes összegére, de minden alkalommal, amikor az aktuális érték a tömb következő számára változik, jobbra haladva.
- Ha már nincs több szám a tömbben, a módszer visszaadja a teljes értéket.
A Reduce Method in JavaScript ES5 verziója
Ha még soha nem használta az ES6 szintaxist, ne hagyja, hogy a fenti példa megfélemlítse. Pontosan ugyanaz, mint az írás:
var euros = [29.76, 41.85, 46.5]; var sum = euros.reduce( function(total, amount){ return total + amount }); sum // 118.11
Az általunk használt const
helyett var
, és cserélje ki a szót function
a „kövér nyíl” ( =>
), miután a paramétereket, és elhagyjuk a „visszatérés”.
A többi példához az ES6 szintaxist fogom használni, mivel tömörebb és kevesebb helyet hagy a hibáknak.
Átlag megtalálása a Reduce módszerrel a JavaScript-ben
Az összeg naplózása helyett az összeget el lehet osztani a tömb hosszával, mielőtt visszaadná a végső értéket.
Ennek módja a redukciós módszer többi argumentumának kihasználása. Ezen érvek közül az első az index . Hasonlóan a for-ciklushoz, az index arra utal, hogy hányszor redukálta a tömböt a hurok. Az utolsó érv maga a tömb .
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
Térkép és szűrés csökkentéseként
Ha a csökkentés funkciót használhatja egy átlag leköpéséhez, akkor azt bármilyen módon használhatja.
Például, akkor megduplázza a teljes, vagy fél minden szám, mielőtt felvenné őket együtt, vagy használjon egy if belül szűkítő csak hozzá számokat, amelyek nagyobbak, mint 10. A lényeg az, hogy az csökkentse Módszer JavaScript ad egy mini CodePen, ahová beírhatja a kívánt logikát. Ez meg fogja ismételni a logika minden összeget a tömböt, majd visszatér egy értékkel.
A helyzet az, hogy nem mindig kell egyetlen értéket visszaadni. Csökkenthet egy tömböt egy új tömbbe.
Például lehetővé teszi az összegek tömbjének csökkentését egy másik tömbbe, ahol minden összeg megduplázódik. Ehhez be kell állítanunk az akkumulátorunk kezdeti értékét egy üres tömbre.
A kezdeti érték a teljes paraméter értéke, amikor a csökkentés megkezdődik. A kezdőértéket vesszővel kell kiegészíteni, amelyet a kezdőérték követ, majd a zárójelben, de a göndör zárójelek után ( az alábbi példában félkövérrel ).
const average = euros.reduce((total, amount, index, array) => { total += amount return total/array.length }, 0);
Korábbi példákban a kezdeti érték nulla volt, ezért kihagytam. A kezdeti érték elhagyásával az összesítés alapértelmezés szerint a tömb első összege lesz.
Ha a kezdeti értéket üres tömbre állítjuk, akkor az egyes összegeket belehelyezhetjük az összesbe . Ha egy értéktömböt egy másik tömbbe akarunk redukálni, ahol minden érték megduplázódik, akkor meg kell tolnunk az összeget * 2. Ezután visszaadjuk az összeget, amikor már nincs több tolandó összeg.
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]
Hoztunk létre egy új tömböt, ahol minden összeg megduplázódik. Kiszűrhetnénk azokat a számokat is, amelyeket nem akarunk duplázni, ha egy reduktorunkba belefoglalunk egy if utasítást.
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 ]
Ezek a műveletek a térkép és a szűrési módszerek, amelyeket redukciós módszerként írnak át.
Ezeknél a példáknál érdemesebb lenne térképet vagy szűrőt használni, mert ezek használata egyszerűbb. A redukció használatának előnye akkor jelenik meg, ha együtt szeretne feltérképezni és szűrni, és rengeteg adatra van szüksége.
Ha összekapcsolja a térképet és szűr, akkor kétszer végzi a munkát. Minden egyes értéket kiszűr, majd feltérképezi a fennmaradó értékeket. A redukcióval egyetlen lépésben szűrhet, majd feltérképezhet.
Használjon térképet és szűrőt, de amikor sok metódust kezd el láncolni, most már tudja, hogy gyorsabb az adatok csökkentése.
Tally létrehozása a Reduce módszerrel a JavaScript-ben
Használja, ha : Van egy elemgyűjteménye, és szeretné tudni, hogy az egyes elemek közül hány van a gyűjteményben.
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 }
A tömb elemeinek összeszámolásához a kezdeti értékünknek üres objektumnak kell lennie, nem pedig egy üres tömbnek, mint az utolsó példában volt.
Mivel egy objektumot fogunk visszaadni, ezért kulcs-érték párokat tárolhatunk az összesben.
fruitBasket.reduce( (tally, fruit) => { tally[fruit] = 1; return tally; }, {})
Első lépésünkben azt akarjuk, hogy az első kulcs neve legyen a jelenlegi értékünk, és 1-es értéket szeretnénk adni neki.
Ez egy olyan tárgyat kap, amelynek kulcsa az összes gyümölcs, mindegyik értéke 1. Szeretnénk, ha megismétlődik az egyes gyümölcsök mennyisége.
Ehhez a második ciklusunkon ellenőrizzük, hogy az összértékünk tartalmaz-e kulcsot a reduktor aktuális gyümölcsével. Ha nem, akkor létrehozzuk. Ha ez megtörténik, akkor eggyel növeljük az összeget.
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 itprev
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.