Ce face Iterable.groupBy
groupBy { ... } calculează pentru fiecare element o cheie (orașul, prima literă, nota) și pune elementul în lista cheii respective. Rezultatul este un Map<K, List<T>>. Cheile apar în ordinea în care au fost întâlnite prima dată, iar în fiecare listă elementele își păstrează ordinea.
A doua formă primește și o funcție pentru valori: în listă nu se pune elementul întreg, ci doar ce întoarce această funcție (de exemplu doar numele elevului).
Dacă vrei doar câte elemente are fiecare grupă, groupingBy { ... }.eachCount() face asta fără să creeze listele.
Parametri
| Parametru | Descriere |
|---|---|
cheie |
Funcția care dă grupa fiecărui element. |
valoare |
Opțional: ce se pune în listă pentru fiecare element (implicit elementul întreg). |
Ce returnează
Un Map<K, List<T>> (sau Map<K, List<V>>) cu ordinea cheilor păstrată.
Exemple
Exemplul 1: Elevi grupați pe orașe
Cheia este orașul. Parcurgem map-ul și afișăm fiecare oraș cu elevii lui.
data class Elev(val nume: String, val oras: String)
fun main() {
val elevi = listOf(
Elev("Ana", "Iași"), Elev("Ion", "Cluj"), Elev("Maria", "Iași"),
Elev("Radu", "Brașov"), Elev("Dan", "Cluj"),
)
val peOrase = elevi.groupBy { it.oras }
for ((oras, grup) in peOrase) {
println("$oras: ${grup.map { it.nume }}")
}
}
Rezultat
Iași: [Ana, Maria]
Cluj: [Ion, Dan]
Brașov: [Radu]
Exemplul 2: Cu funcție pentru valori
Al doilea argument spune ce păstrăm în listă: doar numele. Așa nu mai e nevoie de map la afișare.
data class Elev(val nume: String, val medie: Double)
fun main() {
val elevi = listOf(Elev("Ana", 9.5), Elev("Ion", 6.8), Elev("Maria", 8.2), Elev("Radu", 4.5))
val categorii = elevi.groupBy(
{ if (it.medie >= 9) "excelent" else if (it.medie >= 5) "promovat" else "corigent" },
{ it.nume },
)
println(categorii)
}
Rezultat
{excelent=[Ana], promovat=[Ion, Maria], corigent=[Radu]}
Exemplul 3: Cuvinte după prima literă
Cheia este un caracter. Cheile apar în ordinea primei întâlniri, nu alfabetic; pentru ordine alfabetică folosim toSortedMap().
fun main() {
val cuvinte = listOf("mere", "banane", "măsline", "pere", "brânză", "morcovi")
val dupaLitera = cuvinte.groupBy { it.first() }
println(dupaLitera)
println(dupaLitera.toSortedMap())
}
Rezultat
{m=[mere, măsline, morcovi], b=[banane, brânză], p=[pere]}
{b=[banane, brânză], m=[mere, măsline, morcovi], p=[pere]}
Greșeli frecvente
- Te aștepți ca cheile să fie sortate: sunt în ordinea primei apariții. Sortează cu
toSortedMap()dacă ai nevoie. - Folosești
groupBy { ... }.mapValues { it.value.size }doar pentru numărare:groupingBy { ... }.eachCount()este mai direct.
Comenzi înrudite
Iterable.groupingBy: Pregătește o grupare după cheie; eachCount() numără apoi câte elemente are fiecare cheie (frecvența).Iterable.partition: Împarte colecția în două liste: elementele care îndeplinesc condiția și cele care nu o îndeplinesc.Iterable.associateBy: associateBy face un map cu elementele ca valori și o cheie calculată; associateWith ține elementele ca chei.Map.mapValues: Creează un map nou cu aceleași chei și valori transformate (mapValues) sau cu aceleași valori și chei transformate (mapKeys).Iterable.distinct: Elimină duplicatele și întoarce o listă cu fiecare element o singură dată, în ordinea primei apariții.