Treci la conținutul principal

Gruparea unei colecții

Gruparea înseamnă împărțirea elementelor în grupuri. Alegi o cheie pentru fiecare element, iar toate elementele cu aceeași cheie ajung în același grup.

Cheia este calculată de o funcție mică ce primește un element și returnează cheia lui. De exemplu, prima literă a unui cuvânt.

Go nu are o metodă groupBy integrată pentru slice-uri. Modul natural de a grupa în Go este un map ale cărui chei sunt cheile de grup și ale cărui valori sunt slice-uri de elemente: map[K][]T. Îl umpli cu o buclă for și cu append() sau scrii o singură dată micul helper generic de mai jos și îl refolosești.

Un map nu are o ordine fixă, dar fmt.Println() afișează un map sortat după cheie. Așa că rezultatul afișat arată mereu la fel.

Sintaxa helperului generic GroupBy

T este tipul elementului, iar K este tipul cheii. K trebuie să fie comparable, pentru că cheile unui map trebuie să suporte ==. Pentru fiecare element, helperul apelează key() și adaugă elementul la slice-ul stocat sub acea cheie. Adăugarea la o cheie care nu există încă pornește pur și simplu un slice nou.

main.go
func GroupBy[T any, K comparable](items []T, key func(T) K) map[K][]T {
  groups := make(map[K][]T)
  for _, v := range items {
    k := key(v)
    groups[k] = append(groups[k], v)
  }
  return groups
}

Grupare după cheie

Cea mai simplă grupare păstrează elementele așa cum sunt și decide doar în ce grup ajunge fiecare.

Trimite slice-ul și o funcție de cheie helperului GroupBy. Rezultatul este un map de la cheie la slice-ul cu elementele care au acea cheie. Elementele dintr-un grup păstrează ordinea pe care o aveau în datele de intrare.

Uneori vrei să schimbi elementele în timp ce le grupezi, de exemplu să le stochezi cu majuscule. Go nu are un parametru valueTransform pentru asta. Scrie tu bucla: calculezi cheia, calculezi valoarea nouă și adaugi valoarea nouă în grup.

Grupează cuvintele după prima literă

Funcția de cheie ia prima literă a cuvântului cu w[:1] și o transformă în majusculă cu strings.ToUpper(). Cuvintele care încep cu aceeași literă ajung în același slice.

Prompt
Scrie un helper generic GroupBy care primește un slice și o funcție de cheie și returnează un map de la cheie la un slice cu elementele care au acea cheie. Folosește-l pe cuvintele one, two, three, four, five, cu prima literă scrisă cu majusculă drept cheie. Afișează map-ul.
Ieșire: program Go și rezultatul capturat
Group words by first letter

Grupează și schimbă valorile

Cheia este prima literă scrisă cu minusculă. Valoarea stocată este cuvântul întreg scris cu majuscule. O buclă for simplă face ambii pași și adaugă la groups[key].

Prompt
Grupează cuvintele one, two, three, four, five după prima lor literă scrisă cu minusculă. Păstrează fiecare cuvânt în grupul său scris cu majuscule, nu așa cum era. Folosește o buclă și un map de la string la un slice de string-uri, apoi afișează map-ul.
Ieșire: program Go și rezultatul capturat
Group and change the values

Numără fiecare grup

Deseori nu ai nevoie de elementele fiecărui grup, ci doar de câte sunt.

Go nu are groupingBy() sau eachCount(). Folosește în schimb un map[string]int. Citirea unei chei care nu se află în map dă 0, deci counts[key]++ funcționează chiar și pentru primul element al unui grup.

Numără cuvintele pentru fiecare primă literă

Fiecare cuvânt adaugă 1 la numărătoarea primei sale litere. Map-ul ajunge să aibă câte un număr pentru fiecare literă.

Prompt
Numără câte dintre cuvintele one, two, three, four, five încep cu fiecare literă. Folosește un map de la prima literă la un int și crește numărătoarea pentru fiecare cuvânt. Afișează map-ul.
Ieșire: program Go și rezultatul capturat
Count words per first letter

Fold și reduce pe fiecare grup

A face fold pe 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.

Go nu are fold() sau aggregate() pentru grupuri. Modul Go este un map care ține valoarea curentă a fiecărui grup. Pentru fiecare element, calculezi cheia lui și actualizezi valoarea stocată sub acea cheie.

Când valoarea curentă are o valoare de pornire, precum 0 pentru o sumă, o cheie lipsă îți dă deja acel start. Când primul element trebuie el însuși să pornească valoarea, verifici cu tiparul value, ok := m[key] dacă cheia există deja.

Suma fiecărui grup

Fiecare număr este pus în grupul "par" sau "impar" și adăugat la suma acelui grup cu sums[key] += n. O cheie nouă pornește de la 0, deci nu este nevoie de un caz special.

Prompt
Ia numerele 3, 4, 5, 6, 7, 8 și pune fiecare număr în grupul „par” sau „impar”. În loc să păstrezi numerele, adaugă fiecare număr la suma curentă a grupului său, într-un map de la string la int. Afișează map-ul.
Ieșire: program Go și rezultatul capturat
Sum each group

Construiește un string pentru fiecare grup

Primul număr al unui grup pornește string-ul. Fiecare număr următor este alipit cu "+". Indicatorul exists de la chains[key] distinge cele două cazuri. strconv.Itoa() transformă un număr în text.

Prompt
Ia numerele 3, 4, 5, 6, 7, 8 și pune fiecare număr în grupul „par” sau „impar”. Pentru fiecare grup construiește pas cu pas un string: primul număr pornește string-ul, iar fiecare număr următor este adăugat cu un „+” în față, rezultând un text precum 3+5+7. Afișează map-ul de la numele grupului la string.
Ieșire: program Go și rezultatul capturat
Build a string per group