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.

Python îți oferă direct pe cele mai des folosite, ca funcții încorporate. len() numără elementele, min() și max() găsesc cel mai mic și cel mai mare element, iar sum() le adună.

Atenție: min() și max() ridică o eroare ValueError pe o listă goală și programul se oprește. Verifică mai întâi len(s) > 0 când lista poate fi goală.

Pentru a combina elementele unul câte unul există functools.reduce(). Ea păstrează o valoare curentă, acumulatorul, și apelează funcția ta cu acumulatorul și, pe rând, cu fiecare element. O singură funcție acoperă ceea ce multe limbaje împart în reduce și fold: fără al treilea argument pornește de la primul element, iar cu el pornește de la acea valoare inițială.


Agregări de bază

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

  • len(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.
  • sum(numbers) adună toate elementele. Media este suma împărțită la numărul de elemente; împărțirea cu / păstrează mereu partea zecimală.

Uneori cel mai mic sau cel mai mare element trebuie ales după o regulă, nu după valoarea lui. Pentru asta min() și max() primesc o funcție key=: câștigă elementul cu cea mai mică sau cea mai mare cheie, iar rezultatul este elementul însuși.

Uneori fiecare element trebuie mai întâi transformat cu o funcție, iar rezultatele adunate. sum() primește o expresie generator, așa că sum(f(n) for n in numbers) face asta într-o singură linie.

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

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

Prompt
Pentru numerele 6, 42, 10 și 4 afișează numărul de elemente cu len(), 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 sum(). Pune o etichetă pe fiecare linie, de exemplu „Număr:”, „Maxim:” și așa mai departe.
Ieșire: program Python complet
Count, min, max, sum and average

Minim și maxim după o regulă

min() cu key=lambda n: n % 3 compară resturile. Resturile pentru 5, 42, 10 și 4 sunt 2, 0, 1 și 1, deci câștigă 42. max() cu key=len compară lungimile șirurilor și găsește "three".

Prompt
Pentru numerele 5, 42, 10 și 4 afișează elementul al cărui rest la împărțirea cu 3 este cel mai mic, folosind min() cu key=lambda n: n % 3. Apoi, pentru cuvintele one, two, three, four, afișează-l pe cel mai lung folosind max() cu key=len.
Ieșire: program Python complet
Min and max by a rule

Suma unei funcții aplicate fiecărui element

sum() adună tot ce produce expresia generator. Dublarea lui 5, 42, 10 și 4 dă 122. Înjumătățirea lor cu / dă 30.5.

Prompt
Pentru numerele 5, 42, 10 și 4 afișează suma tuturor elementelor dublate, apoi suma tuturor elementelor înjumătățite cu /, de fiecare dată folosind sum() cu o expresie generator.
Ieșire: program Python complet
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, iar în Python ea este pur și simplu al treilea argument al functools.reduce():

  • reduce(f, items, initial) este un fold: pornește de la valoarea inițială pe care i-o dai. Funcția rulează o dată pentru fiecare element.
  • reduce(f, items) pornește de la primul element. Funcția rulează de la al doilea element încolo, deci primul element nu trece niciodată prin ea.

Asta contează când funcția modifică elementul. Dacă ea dublează fiecare element, reduce() fără valoare inițială lasă primul element neschimbat.

Python nu are un reduce de la dreapta. Ca să faci fold de la dreapta, rulează reduce() peste reversed(items): elementele sosesc de la ultimul la primul, iar funcția primește tot acumulatorul primul și elementul al doilea.

Reduce

reduce() fără valoare inițială ia 5 ca punct de pornire și îi adună 2, 10 și 4. Rezultatul este 21.

Prompt
Folosește functools.reduce fără valoare inițială ca să aduni numerele 5, 2, 10 și 4, astfel încât primul element să fie valoarea de pornire. Afișează rezultatul.
Ieșire: program Python complet
Reduce

Fold

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

Prompt
Folosește functools.reduce cu valoarea inițială 0 ca să adaugi la acumulator fiecare dintre numerele 5, 2, 10 și 4 înmulțit cu 2. Afișează rezultatul.
Ieșire: program Python complet
Fold

Fold comparat cu Reduce

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

Prompt
Definește o funcție add_doubled(acc, element) care returnează acc + element * 2. Apelează functools.reduce pe numerele 5, 2, 10 și 4 o dată fără valoare inițială și o dată cu valoarea inițială 0, și afișează ambele rezultate cu etichetele „Reduce:” și „Fold:”.
Ieșire: program Python complet
Fold versus Reduce

Fold de la dreapta

reversed(numbers) îi dă elementele lui reduce() de la ultimul la primul. La adunare ordinea nu contează, așa că rezultatul este din nou 42.

Prompt
Folosește functools.reduce cu valoarea inițială 0 peste reversed(numbers) ca să aduni fiecare dintre numerele 5, 2, 10 și 4 înmulțit cu 2, parcurgând de la ultimul element la primul. Afișează rezultatul.
Ieșire: program Python complet
Fold from the right

Fold cu index

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

În Python o buclă simplă cu enumerate() îți dă indexul. for idx, element in enumerate(numbers) parcurge lista de la început. for idx, element in reversed(list(enumerate(numbers))) parcurge aceleași perechi index-element de la sfârșit. În interiorul buclei un if verifică indexul și decide dacă elementul se adună.

Fold cu index

Se adună doar elementele de la indexuri pare: la indexul 0 este 5, iar la indexul 2 este 10, deci suma este 15.

Prompt
Adună doar elementele din 5, 2, 10, 4 care se află la un index par. Folosește o buclă for peste enumerate(numbers) și un if pe index. Afișează suma.
Ieșire: program Python complet
Fold with index

Fold cu index de la dreapta

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

Prompt
Adună doar elementele din 5, 2, 10, 4 care se află la un index par, parcurgând de la ultimul index până la 0 cu reversed(list(enumerate(numbers))). Afișează suma.
Ieșire: program Python complet
Fold with index from the right

Reduce sigur

reduce() are nevoie de un prim element de la care să pornească. Pe o listă goală ridică o eroare TypeError și programul se oprește.

În Python, „nu există rezultat” se exprimă prin None. O mică funcție ajutătoare verifică mai întâi lista: când este goală, returnează None în loc să apeleze reduce(). Apelantul verifică apoi dacă a primit None, la fel ca la dict.get() pentru o cheie care lipsește.

Reduce sau None

reduce_or_none returnează 21 pentru numerele 5, 2, 10 și 4, și None pentru o listă goală.

Prompt
Scrie o funcție reduce_or_none(items, f) care returnează None pentru o listă goală și altfel rezultatul lui functools.reduce. Apeleaz-o cu o funcție de adunare pe numerele 5, 2, 10 și 4 și pe o listă goală, și afișează ambele rezultate.
Ieșire: program Python complet
Reduce or None

Fold și Reduce cumulativ

Un fold sau reduce cumulativ nu aruncă pașii intermediari. El salvează acumulatorul după fiecare element, așa că rezultatul este o listă cu toate valorile intermediare.

Python are asta încorporat în itertools.accumulate(). Implicit adună și produce fiecare sumă intermediară. La un reduce cumulativ rezultatul începe cu primul element. Cu argumentul cu nume initial= devine un fold cumulativ: rezultatul începe cu valoarea inițială și are cu un element mai mult decât datele de intrare.

Reduce cumulativ

Numerele de la 0 la 5 sunt adunate unul câte unul. accumulate() păstrează fiecare sumă de pe parcurs: [0, 1, 3, 6, 10, 15].

Prompt
Folosește itertools.accumulate ca să aduni numerele de la 0 la 5 unul câte unul și afișează lista cu fiecare sumă intermediară.
Ieșire: program Python complet
Running reduce

Fold cumulativ

La fel, dar cu initial=10. Rezultatul începe cu 10 însuși și are cu un element mai mult decât datele de intrare: [10, 10, 11, 13, 16, 20, 25].

Prompt
Folosește itertools.accumulate cu initial=10 pe numerele de la 0 la 5 și afișează lista sumelor intermediare, care începe cu 10 și are cu un element mai mult decât datele de intrare.
Ieșire: program Python complet
Running fold