Gruparea unei colecții
Gruparea înseamnă împărțirea elementelor în „găleți”. Alegi o cheie pentru fiecare element, iar toate elementele cu aceeași cheie ajung în aceeași găleată.
Cheia este calculată de o expresie mică, care primește un element și returnează cheia lui. De exemplu, prima literă a unui cuvânt.
Python nu are o metodă încorporată group_by pentru liste. Modul firesc de a grupa este un dicționar ale cărui chei sunt cheile grupurilor și ale cărui valori sunt liste de elemente. Îl umpli cu o buclă for și setdefault(), sau lași collections.defaultdict(list) să creeze listele goale în locul tău.
Un dicționar își păstrează intrările în ordinea inserării, așa că grupurile apar în ordinea în care au fost întâlnite primele lor elemente. Rezultatul afișat arată mereu la fel.
Gruparea după cheie
Cea mai simplă grupare păstrează elementele așa cum sunt și decide doar în ce găleată ajunge fiecare.
setdefault(key, []) returnează lista stocată sub cheie și, dacă cheia nu există încă, stochează mai întâi o listă nouă, goală. Astfel, groups.setdefault(key, []).append(w) funcționează chiar și pentru primul element al unui grup. Elementele dintr-un grup păstrează ordinea pe care o aveau în datele de intrare.
Uneori vrei să modifici elementele în timpul grupării, de exemplu să le stochezi cu litere mari. Calculează cheia, calculează noua valoare și adaugă noua valoare în grup. Cu un defaultdict(list) este suficient un simplu groups[key].append(value).
Gruparea cuvintelor după prima literă
Cheia este prima literă a cuvântului, w[0], transformată în literă mare cu upper(). Cuvintele care încep cu aceeași literă ajung în aceeași listă.
Ieșire: program Python complet
words = ["one", "two", "three", "four", "five"]
# setdefault dă lista unei chei, stocând mai întâi una nouă, goală, dacă e nevoie
by_first_letter = {}
for w in words:
key = w[0].upper()
by_first_letter.setdefault(key, []).append(w)
print(by_first_letter)
Gruparea și modificarea valorilor
Cheia este prima literă, mică. Valoarea stocată este întregul cuvânt cu litere mari. Un defaultdict(list) începe fiecare grup nou ca listă goală; dict() îl transformă înapoi într-un dicționar simplu, pentru o afișare curată.
Ieșire: program Python complet
from collections import defaultdict
words = ["one", "two", "three", "four", "five"]
# un defaultdict creează singur o listă goală pentru fiecare cheie nouă
groups = defaultdict(list)
for w in words:
key = w[0] # prima literă, mică
value = w.upper() # valoarea stocată în grup
groups[key].append(value)
print(dict(groups))
Numărarea fiecărui grup
Adesea nu ai nevoie de elementele fiecărui grup, ci doar de câte sunt.
Biblioteca standard are un instrument exact pentru asta: collections.Counter. Îi dai cheile și returnează un obiect asemănător unui dicționar, de la cheie la număr. Citirea unei chei care nu se află într-un Counter dă 0.
Când este afișat, un Counter arată mai întâi numerele cele mai mari.
Numărarea cuvintelor după prima literă
Fiecare cuvânt este transformat în prima sa literă, iar Counter numără literele. Literele t și f apar amândouă de două ori, așa că sunt afișate înaintea lui o.
Ieșire: program Python complet
from collections import Counter
words = ["one", "two", "three", "four", "five"]
# Counter numără fiecare cheie în locul tău; o cheie lipsă are numărul 0
counts = Counter(w[0] for w in words)
print(counts)
Pliere și reducere pe grup
A plia un grup înseamnă a combina elementele lui într-o singură valoare, pas cu pas. Un total curent este exemplul clasic: pornești de la 0 și aduni fiecare element.
Python nu are fold() sau aggregate() pentru grupuri. Folosește un dicționar care păstrează valoarea curentă a fiecărui grup. Pentru fiecare element, calculează-i cheia și actualizează valoarea stocată sub acea cheie.
Când valoarea curentă are o valoare de pornire, cum ar fi 0 pentru o sumă, get(key, 0) îți dă acea valoare de pornire pentru o cheie lipsă. Când chiar primul element trebuie să înceapă valoarea, verifică cu operatorul in dacă cheia există deja; merge și get(key), care dă None pentru o cheie lipsă.
Suma fiecărui grup
Fiecare număr este pus în grupul "even" sau "odd" și adunat la suma acelui grup. sums.get(key, 0) pornește o cheie nouă de la 0, așa că nu e nevoie de niciun caz special.
Ieșire: program Python complet
numbers = [3, 4, 5, 6, 7, 8]
# get(key, 0) dă 0 pentru un grup nou, așa că adunarea funcționează imediat
sums = {}
for n in numbers:
key = "even" if n % 2 == 0 else "odd"
sums[key] = sums.get(key, 0) + n
print(sums)
Construirea unui șir pentru fiecare grup
Primul număr al unui grup începe șirul. Fiecare număr următor este alipit cu "+". Verificarea key not in chains deosebește cele două cazuri. str() transformă un număr în text.
Ieșire: program Python complet
numbers = [3, 4, 5, 6, 7, 8]
chains = {}
for n in numbers:
key = "even" if n % 2 == 0 else "odd"
# primul număr al unui grup începe șirul; următoarele sunt adăugate cu "+"
if key not in chains:
chains[key] = str(n)
else:
chains[key] = chains[key] + "+" + str(n)
print(chains)