Treci la conținutul principal

Operații de agregare

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

PHP ți le oferă pe cele obișnuite ca funcții încorporate. count() numără elementele, min() și max() găsesc cel mai mic și cel mai mare element, iar array_sum() le adună.

Atenție: min() și max() aruncă o excepție ValueError pe un tablou gol („must contain at least one element”), iar programul se oprește dacă nu o prinzi. Verifică întâi count($s) > 0 atunci când tabloul poate fi gol. array_sum([]) este pur și simplu 0.

Pentru combinarea elementelor unul câte unul există array_reduce($items, $callback, $initial). Ea păstrează o valoare curentă, acumulatorul, și apelează funcția ta cu acumulatorul și, pe rând, cu fiecare element. Acumulatorul pornește de la $initial — iar dacă lași $initial deoparte, pornește de la null, nu de la primul element. Această pagină arată ce înseamnă asta și cum obții ambele stiluri de combinare, numite adesea fold și reduce.


Agregări de bază

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

  • count($numbers) dă numărul de elemente.
  • min($numbers) și max($numbers) dau cel mai mic și cel mai mare element. Funcționează pentru numere și pentru șiruri de caractere.
  • array_sum($numbers) adună fiecare element. Media este suma împărțită la numărul de elemente. Operatorul / din PHP păstrează partea zecimală atunci când împărțirea nu este exactă, așa că 62 / 4 este 15.5.

Uneori cel mai mic sau cel mai mare element trebuie ales după o regulă, nu după valoarea însăși. min() și max() nu primesc nicio regulă, dar array_reduce() poate păstra elementul mai bun: la fiecare pas compară cel mai bun element de până acum cu cel curent și păstrează câștigătorul.

Uneori fiecare element trebuie convertit întâi cu o funcție, iar rezultatele adunate. Înlănțuie două funcții încorporate: array_map() convertește, array_sum() adună.

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

Pentru numerele 6, 42, 10 și 4 afișează numărul de elemente cu count(), cel mai mare și cel mai mic element cu max() și min(), iar suma cu array_sum(). Media este 62 / 4 = 15.5.

Prompt
Pentru numerele 6, 42, 10 și 4 afișează numărul de elemente cu count(), cel mai mare și cel mai mic element cu max() și min(), media ca sumă împărțită la numărul de elemente și suma cu array_sum(). Etichetează fiecare linie, de exemplu „Count:”, „Max:” și așa mai departe.
Ieșire: script PHP
Count, min, max, sum and average

Minim și maxim după o regulă

Primul array_reduce() păstrează elementul cu restul mai mic la % 3. Resturile numerelor 5, 42, 10 și 4 sunt 2, 0, 1 și 1, așa că 42 câștigă. Al doilea păstrează șirul de caractere mai lung și găsește "three". Nu se dă nicio valoare inițială, deci $best pornește de la null, iar verificarea $best === null lasă primul element să câștige prima rundă. La egalitate rămâne elementul dinainte.

Prompt
Pentru numerele 5, 42, 10 și 4 găsește elementul al cărui rest la împărțirea cu 3 este cel mai mic, folosind array_reduce care păstrează elementul mai bun (pornind de la null). Apoi, pentru cuvintele one, two, three, four găsește în același fel cel mai lung. Afișează ambele rezultate.
Ieșire: script PHP
Min and max by a rule

Suma unei funcții de fiecare element

array_map() convertește fiecare element, array_sum() adună rezultatele. Dublarea numerelor 5, 42, 10 și 4 dă 122. Înjumătățirea lor dă 30.5.

Prompt
Pentru numerele 5, 42, 10 și 4 afișează suma fiecărui element dublat, apoi suma fiecărui element înjumătățit, de fiecare dată cu array_sum peste array_map.
Ieșire: script PHP
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.

Diferența este valoarea de pornire:

  • Un fold pornește de la o valoare inițială pe care i-o dai tu. Funcția rulează o dată pentru fiecare element. În PHP asta este exact array_reduce($items, $f, $initial).
  • Un reduce pornește de la primul element. Funcția rulează începând cu al doilea element, așa că primul element nu trece niciodată prin ea.

În ciuda numelui, array_reduce() este întotdeauna un fold. Fără al treilea argument pornește de la null, iar în aritmetică null contează ca 0 — deci funcția rulează totuși pentru fiecare element. Un reduce adevărat ia primul element ca pornire și pliază restul: array_reduce(array_slice($items, 1), $f, $items[0]). O mică funcție ajutătoare reduce() împachetează linia aceasta.

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

PHP nu are un reduce dinspre dreapta. Pentru a plia dinspre dreapta, dă-i lui array_reduce() tabloul inversat de array_reverse(): elementele sosesc de la ultimul la primul, iar funcția primește tot acumulatorul primul și elementul al doilea.

Reduce

Funcția ajutătoare reduce() ia 5 ca pornire și pliază în el 2, 10 și 4. Rezultatul este 21.

Prompt
Scrie o funcție ajutătoare reduce care pornește de la primul element al unui tablou și combină restul în el cu array_reduce peste array_slice($items, 1) și valoarea inițială $items[0]. Folosește-o pentru a aduna numerele 5, 2, 10 și 4 și afișează rezultatul.
Ieșire: script PHP
Reduce

Fold

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

Prompt
Folosește array_reduce cu valoarea inițială 0 pentru a adăuga la acumulator fiecare dintre numerele 5, 2, 10 și 4 înmulțit cu 2. Afișează rezultatul.
Ieșire: script PHP
Fold

Fold față de Reduce

Ambele apeluri folosesc aceeași funcție, acumulatorul plus elementul înmulțit cu 2. reduce() dă 37, pentru că primul element, 5, este pornirea și nu este dublat. array_reduce() cu valoarea inițială 0 dă 42. Dacă ai lăsa 0 deoparte, ar da tot 42: pornirea ar fi null, iar null + 10 este 10.

Prompt
Scrie o funcție ajutătoare reduce care pornește de la primul element (array_reduce peste array_slice($items, 1), cu $items[0] ca valoare inițială). Definește o funcție $addDoubled care returnează $acc + $element * 2. Folosește-o pe numerele 5, 2, 10 și 4 o dată cu reduce() și o dată cu array_reduce și valoarea inițială 0, apoi afișează ambele rezultate cu etichetele „Reduce:” și „Fold:”.
Ieșire: script PHP
Fold versus Reduce

Fold dinspre dreapta

array_reverse($numbers) dă elementele lui array_reduce() de la ultimul până la primul. Adunarea nu ține cont de ordine, așa că rezultatul este din nou 42.

Prompt
Folosește array_reduce cu valoarea inițială 0 peste array_reverse($numbers) pentru a adăuga fiecare dintre numerele 5, 2, 10 și 4 înmulțit cu 2, parcurgând de la ultimul element către primul. Afișează rezultatul.
Ieșire: script PHP
Fold from the right

Fold cu index

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

Funcția de apel a lui array_reduce() nu vede niciodată cheile, dar o buclă foreach simplă le vede. foreach ($numbers as $idx => $element) parcurge de la început. array_reverse($numbers, true) inversează tabloul, dar păstrează cheile originale, pentru că al doilea argument este true — așa că un foreach peste el parcurge de la sfârșit și vede totuși indexul real al fiecărui element. În buclă, un if verifică indexul și decide dacă elementul se adună.

Fold cu index

Se adună numai elementele de pe indexurile pare: indexul 0 ține 5 și indexul 2 ține 10, deci suma este 15.

Prompt
Adună numai elementele din 5, 2, 10, 4 care se află pe un index par. Folosește o buclă foreach cu indexul și un if pe index. Afișează suma.
Ieșire: script PHP
Fold with index

Fold cu index dinspre dreapta

Aceeași regulă, dar bucla pornește de la indexul 3 și coboară până la 0. Rezultatul este tot 15.

Prompt
Adună numai elementele din 5, 2, 10, 4 care se află pe un index par, parcurgând de la ultimul index până la 0 cu un foreach peste array_reverse($numbers, true), care păstrează cheile originale. Afișează suma.
Ieșire: script PHP
Fold with index from the right

Reduce în siguranță

Un reduce are nevoie de un prim element de la care să pornească. Pe un tablou gol, funcția ajutătoare reduce() ar citi $items[0], care nu există: PHP afișează un avertisment („Undefined array key 0”) și continuă cu null.

Modul PHP de a spune „nu există rezultat” este null. O mică funcție ajutătoare verifică întâi tabloul: când este gol, returnează null fără să atingă $items[0]. Apelantul verifică apoi dacă este null, exact așa cum $map[$key] ?? $default tratează o cheie lipsă. array_reduce() se comportă deja așa: pe un tablou gol returnează valoarea sa inițială, care este null dacă nu dai niciuna.

Reduce sau null

reduceOrNull() returnează 21 pentru numerele 5, 2, 10 și 4, și null pentru un tablou gol. Ultima linie arată că array_reduce() fără valoare inițială returnează și el null pentru un tablou gol. json_encode() afișează null ca fiind cuvântul null.

Prompt
Scrie o funcție reduceOrNull care returnează null pentru un tablou gol și altfel pornește de la primul element și pliază restul cu array_reduce. Apelează-o cu o funcție de adunare pe numerele 5, 2, 10 și 4 și pe un tablou gol. Apoi apelează array_reduce pe tabloul gol fără valoare inițială. Afișează toate cele trei rezultate cu json_encode.
Ieșire: script PHP
Reduce or null

Fold și Reduce cu valori intermediare

Un fold sau un reduce cu valori intermediare nu aruncă pașii dintre. Salvează acumulatorul după fiecare element, așa că rezultatul este un tablou cu toate valorile intermediare.

PHP nu are o funcție încorporată pentru asta. Păstrează o variabilă sumă și adaug-o la un tablou de rezultate cu $result[] = $sum într-o buclă foreach. Pentru un reduce cu valori intermediare, rezultatul începe cu primul element. Pentru un fold cu valori intermediare, rezultatul începe cu valoarea inițială și are un element mai mult decât intrarea.

Reduce cu valori intermediare

Numerele de la 0 la 5 sunt adunate unul câte unul. Tabloul de rezultate ține fiecare sumă de pe drum: 0, 1, 3, 6, 10, 15.

Prompt
Pentru numerele de la 0 la 5, pornește o sumă de la primul element și adaugă restul unul după altul într-o buclă foreach, salvând fiecare sumă intermediară într-un tablou de rezultate care începe cu primul element. Afișează rezultatul cu implode.
Ieșire: script PHP
Running reduce

Fold cu valori intermediare

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

Prompt
Pentru numerele de la 0 la 5, pornește o sumă de la valoarea inițială 10 și adaugă fiecare element unul după altul într-o buclă foreach, salvând fiecare sumă intermediară într-un tablou de rezultate care începe cu 10. Afișează rezultatul cu implode.
Ieșire: script PHP
Running fold