Treci la conținutul principal

Operații de agregare

O operație de agregare transformă o întreagă colecție într-o singură valoare. Exemple sunt numărul de elemente, suma lor, cel mai mare element sau toate elementele combinate într-un singur rezultat.

Tablourile îți oferă direct câteva dintre acestea. numbers.length numără elementele. Math.max() și Math.min() găsesc cel mai mare și cel mai mic număr; le dai elementele cu Math.max(...numbers). Pentru o sumă sau o medie nu există o metodă: combini elementele cu reduce().

Ai grijă cu tablourile goale. Math.max() fără valori returnează -Infinity, iar Math.min() returnează Infinity, deci verifică numbers.length > 0 atunci când tabloul ar putea fi gol.

Multe limbaje au metode separate fold și reduce pentru a combina elementele unul câte unul. Aici ambele sunt aceeași metodă, reduce(), iar diferența stă doar în faptul că treci sau nu o valoare inițială. reduceRight() face aceeași parcurgere, de la ultimul element spre primul.


Agregări de bază

Cele mai obișnuite agregări sunt numărul de elemente, minimul, maximul, suma și media.

  • numbers.length dă numărul de elemente.
  • Math.max(...numbers) și Math.min(...numbers) dau cel mai mare și cel mai mic număr. Funcționează doar pentru numere.
  • Suma este un reduce() care adaugă fiecare element la un total curent. Media este suma împărțită la numărul de elemente; împărțirea păstrează partea zecimală, deci 62 / 4 este 15.5.

Uneori cel mai mic sau cel mai mare element trebuie ales după o regulă, nu după valoarea în sine. reduce() face și asta: la fiecare pas păstrezi pe cel mai bun dintre cele două elemente. Acest lucru funcționează și pentru cuvinte și obiecte, unde Math.min() nu poate ajuta.

Uneori fiecare element trebuie transformat mai întâi într-un număr, iar rezultatele adunate. Și asta este tot un reduce(): adaugi valoarea calculată în loc de elementul însuși.

Număr de elemente, minim, maxim, sumă și medie

Pentru numerele 6, 42, 10 și 4 programul afișează numărul de elemente cu length, cel mai mare și cel mai mic cu Math.max() și Math.min(), iar suma dintr-un reduce(). Media este 62 / 4 = 15.5.

Prompt
Scrie un program TypeScript care ia numerele 6, 42, 10 și 4 și afișează numărul de elemente, cel mai mare, cel mai mic, media și suma, fiecare pe câte o linie, cu o etichetă precum „Număr:”. Folosește length, Math.max, Math.min și un reduce() pentru sumă.
Ieșire: program TypeScript și rezultatul capturat
Count, min, max, sum and average

Minim și maxim după o regulă

Primul reduce() păstrează elementul cu restul mai mic la împărțirea cu 3. Resturile lui 5, 42, 10 și 4 sunt 2, 0, 1 și 1, deci câștigă 42. Al doilea păstrează cuvântul mai lung și găsește "three".

Prompt
Scrie un program TypeScript care afișează elementul cu cel mai mic rest la împărțirea cu 3 dintre numerele 5, 42, 10 și 4, folosind reduce() pentru a păstra elementul mai bun. Apoi afișează, în același mod, cel mai lung dintre cuvintele one, two, three, four.
Ieșire: program TypeScript și rezultatul capturat
Min and max by a rule

Suma unei funcții aplicate fiecărui element

Callback-ul adaugă la total o valoare calculată, în loc de elementul însuși. Dublarea lui 5, 42, 10 și 4 dă 122. Înjumătățirea lor dă 30.5, pentru că împărțirea păstrează partea zecimală.

Prompt
Scrie un program TypeScript care ia numerele 5, 42, 10 și 4 și folosește reduce() cu valoarea inițială 0 pentru a afișa suma fiecărui element înmulțit cu 2, iar apoi suma fiecărui element împărțit la 2.
Ieșire: program TypeScript și rezultatul capturat
Sum of a function of each element

Fold și Reduce

Fold și reduce combină toate elementele într-o singură valoare, pas cu pas. Ele păstrează o valoare curentă numită acumulator. Pentru fiecare element apelează o funcție cu acumulatorul și elementul, iar funcția returnează noul acumulator.

Aici ambele sunt aceeași metodă. Diferența este al doilea argument al lui reduce():

  • reduce(fn, initial) este un fold. Pornește de la valoarea inițială pe care i-o dai, deci funcția rulează o dată pentru fiecare element.
  • reduce(fn) este un reduce. Pornește de la primul element, deci funcția rulează începând cu al doilea element, iar primul element nu trece niciodată prin ea.

Asta contează atunci când funcția modifică elementul. Dacă dublează fiecare element, reduce(fn) lasă primul element așa cum este.

Contează și pentru tablourile goale. reduce(fn, initial) returnează pur și simplu valoarea inițială, în timp ce reduce(fn) nu are de unde să pornească și aruncă un TypeError.

Pentru a combina dinspre celălalt capăt, folosește reduceRight(): aceeași metodă, parcurgând de la ultimul element spre primul.

Reduce

reduce() fără valoare inițială ia 5 ca start și adaugă la el 2, 10 și 4, deci rezultatul este 21. Același apel pe un tablou gol aruncă o eroare, iar programul afișează mesajul pe care aceasta îl poartă: Reduce of empty array with no initial value.

Prompt
Scrie un program TypeScript care adună numerele 5, 2, 10 și 4 cu reduce() fără valoare inițială, astfel încât primul element să fie startul, și afișează rezultatul. Apoi apelează același reduce() pe un tablou gol în interiorul unui try/catch și afișează mesajul erorii.
Ieșire: program TypeScript și rezultatul capturat
Reduce

Fold

Aici reduce() primește valoarea inițială 0 și adaugă fiecare element înmulțit cu 2. Fiecare element este dublat: 10 + 4 + 20 + 8 = 42.

Prompt
Scrie un program TypeScript care folosește reduce() cu valoarea inițială 0 pe numerele 5, 2, 10 și 4, adunând fiecare element înmulțit cu 2, și afișează rezultatul.
Ieșire: program TypeScript și rezultatul capturat
Fold

Fold față de Reduce

Ambele apeluri folosesc aceeași funcție, suma plus elementul înmulțit cu 2. Fără valoare inițială rezultatul este 37, pentru că primul element, 5, este startul și nu este dublat. Cu valoarea inițială 0 rezultatul este 42.

Prompt
Scrie un program TypeScript care rulează de două ori aceeași funcție, suma plus elementul înmulțit cu 2, peste numerele 5, 2, 10 și 4: o dată cu reduce() fără valoare inițială, o dată cu valoarea inițială 0. Afișează ambele rezultate cu etichetele „Reduce:” și „Fold:”, ca să arăți că fără valoare inițială primul element nu este niciodată dublat.
Ieșire: program TypeScript și rezultatul capturat
Fold versus Reduce

Fold dinspre dreapta

reduceRight() parcurge tabloul de la ultimul element spre primul. Adunării nu îi pasă de ordine, deci rezultatul este din nou 42.

Prompt
Scrie un program TypeScript care folosește reduceRight() cu valoarea inițială 0 pe numerele 5, 2, 10 și 4, adunând fiecare element înmulțit cu 2, și afișează rezultatul.
Ieșire: program TypeScript și rezultatul capturat
Fold from the right

Fold cu index

Uneori contează poziția unui element, nu doar valoarea lui.

Callback-ul lui reduce() primește indexul ca al treilea argument, după acumulator și element. O condiție pe acel index decide apoi ce se întâmplă cu elementul. reduceRight() transmite aceiași indecși; doar că îi vizitează dinspre sfârșit.

Fold cu index

Se adună doar elementele de la indecși pari: indexul 0 conține 5, iar indexul 2 conține 10, deci suma este 15.

Prompt
Scrie un program TypeScript care folosește reduce() peste numerele 5, 2, 10 și 4 și adună doar elementele al căror index este par, folosind argumentul index al callback-ului. Afișează suma.
Ieșire: program TypeScript și rezultatul capturat
Fold with index

Fold cu index dinspre dreapta

Aceeași regulă cu reduceRight(). Callback-ul vede mai întâi indexul 3 și la final indexul 0, iar rezultatul este tot 15.

Prompt
Scrie un program TypeScript care folosește reduceRight() peste numerele 5, 2, 10 și 4 și adună doar elementele al căror index este par. Afișează suma.
Ieșire: program TypeScript și rezultatul capturat
Fold with index from the right

Reduce în siguranță

reduce() fără valoare inițială are nevoie de un prim element de la care să pornească. Pe un tablou gol aruncă un TypeError și oprește programul.

O soluție este o valoare inițială. Cealaltă este să spui cinstit „nu există niciun rezultat”: verifici mai întâi lungimea și returnezi undefined. Tipul returnat devine atunci number | undefined, ceea ce îl face pe apelant să se gândească la cazul gol, iar ?? pune dintr-un singur pas o valoare de rezervă în locul lui undefined.

Reduce care poate returna undefined

sumOrUndefined() returnează 21 pentru numerele 5, 2, 10 și 4 și undefined pentru un tablou gol. sumOrUndefined(empty) ?? 0 transformă acel undefined în 0.

Prompt
Scrie un program TypeScript cu o funcție sumOrUndefined care returnează number | undefined: returnează undefined pentru un tablou gol în loc să arunce o eroare, iar altfel suma obținută cu reduce(). Afișează rezultatul pentru numerele 5, 2, 10 și 4, apoi pentru un tablou gol, apoi cazul gol cu ?? 0 ca valoare de rezervă.
Ieșire: program TypeScript și rezultatul capturat
Reduce that can return undefined

Fold și Reduce parțiale

Un fold sau un reduce parțial nu aruncă pașii intermediari. Păstrează acumulatorul după fiecare element, deci rezultatul este un tablou cu toate valorile parțiale.

Nu există o metodă pentru asta. Ții o variabilă sumă și o adaugi cu push() într-un tablou rezultat, în interiorul buclei. Pentru un reduce parțial rezultatul începe cu primul element. Pentru un fold parțial începe cu valoarea inițială, deci conține cu un element mai mult decât intrarea.

Reduce parțial

Numerele de la 0 la 5 sunt adunate unul câte unul. Tabloul rezultat conține fiecare sumă de pe parcurs și este afișat pe o singură linie cu join(' '): 0 1 3 6 10 15.

Prompt
Scrie un program TypeScript care ia numerele 0, 1, 2, 3, 4 și 5 și construiește un tablou de sume parțiale: pornește de la primul element și adaugă noua sumă după fiecare element următor. Afișează tabloul pe o singură linie cu join(' ').
Ieșire: program TypeScript și rezultatul capturat
Running reduce

Fold parțial

Același lucru cu valoarea inițială 10. Rezultatul începe chiar cu 10 și conține cu un element mai mult decât intrarea: 10 10 11 13 16 20 25.

Prompt
Scrie un program TypeScript care ia numerele 0, 1, 2, 3, 4 și 5 și construiește un tablou de sume parțiale care începe cu valoarea inițială 10 și adaugă noua sumă după fiecare element. Afișează tabloul pe o singură linie cu join(' ').
Ieșire: program TypeScript și rezultatul capturat
Running fold