Ce face GroupBy
Metoda GroupBy împarte o colecție în grupuri logice pe baza unei chei (o proprietate sau un tuplu de proprietăți), returnând o secvență de grupuri IEnumerable<IGrouping<TKey, TElement>>. Fiecare obiect g rezultat din grupare expune proprietatea g.Key (valoarea cheii după care s-a făcut gruparea) și implementează el însuși IEnumerable<TElement>, astfel încât poți aplica direct pe g metode de agregare precum g.Count(), g.Sum(...), g.Average(...) sau îl poți parcurge cu un foreach.
Atunci când vrei să transformi o colecție într-un dicționar în care cheia este unică (de exemplu ID-ul), folosești .ToDictionary(x => x.Id); când însă mai multe elemente împart aceeași cheie, folosești GroupBy (sau ToLookup(x => x.Categorie) pentru un dicționar imutabil unu-la-mulți).
Parametri, metode și opțiuni
| Parametru / Metodă | Descriere |
|---|---|
source.GroupBy(x => x.Cheie) |
Grupează elementele după cheia returnată de expresia lambda; fiecare grup este un IGrouping<TKey, TSource>. |
grup.Key |
Proprietatea care conține valoarea cheii comune pentru toate elementele din grupul curent. |
source.GroupBy(cheie, (k, elem) => rez) |
Suprascriere care aplică direct o proiecție de agregare pe fiecare cheie k și elementele sale elem. |
source.ToLookup(x => x.Cheie) |
Materializează imediat gruparea într-o structură indexată imutabilă ILookup<TKey, TElement>. |
source.ToDictionary(x => x.Id, x => x) |
Convertește secvența într-un Dictionary<TKey, TValue> (necesită chei strict unice). |
Exemple
Exemplul 1: Raport de vânzări pe categorii cu GroupBy, Count și Sum
Grupăm comenzile după județ, calculăm numărul de comenzi și valoarea totală pentru fiecare grup, apoi ordonăm grupurile descrescător după încasări.
var facturi = new[]
{
new Factura("Cluj", 450m),
new Factura("București", 1200m),
new Factura("Cluj", 850m),
new Factura("Timiș", 600m),
new Factura("București", 950m),
new Factura("Cluj", 300m)
};
var raportJudete = facturi
.GroupBy(f => f.Judet)
.Select(grup => new
{
Judet = grup.Key,
NumarFacturi = grup.Count(),
TotalIncasat = grup.Sum(f => f.Valoare),
Medie = grup.Average(f => f.Valoare)
})
.OrderByDescending(r => r.TotalIncasat);
foreach (var r in raportJudete)
{
Console.WriteLine($"{r.Judet,-10}: {r.NumarFacturi} facturi | Total: {r.TotalIncasat,7:F2} RON | Medie: {r.Medie:F2} RON");
}
record Factura(string Judet, decimal Valoare);
Ieșire în consolă
București : 2 facturi | Total: 2150.00 RON | Medie: 1075.00 RON
Cluj : 3 facturi | Total: 1600.00 RON | Medie: 533.33 RON
Timiș : 1 facturi | Total: 600.00 RON | Medie: 600.00 RON
Exemplul 2: Grupare după o cheie compusă (tuplu) și convertire în Dictionary
Putem grupa după mai multe proprietăți simultan folosind un tuplu (x.An, x.Trimestru).
var evenimente = new[]
{
new { An = 2026, Trimestru = "Q1", Venit = 10000 },
new { An = 2026, Trimestru = "Q1", Venit = 15000 },
new { An = 2026, Trimestru = "Q2", Venit = 22000 }
};
var dictTrimestre = evenimente
.GroupBy(e => (e.An, e.Trimestru))
.ToDictionary(
g => $"{g.Key.An}-{g.Key.Trimestru}",
g => g.Sum(e => e.Venit)
);
foreach (var (perioada, total) in dictTrimestre)
{
Console.WriteLine($"{perioada}: {total} EUR");
}
Ieșire în consolă
2026-Q1: 25000 EUR
2026-Q2: 22000 EUR
Greșeli frecvente
- Apelarea
.ToDictionary(x => x.Categorie)pe o listă în care mai multe elemente au aceeași categorie —ToDictionarycere chei unice și aruncăArgumentException: An item with the same key has already been added. FoloseșteGroupBysauToLookupcând cheile se pot repeta. - Gruparea după un obiect mutabil sau o clasă care nu suprascrie
EqualsșiGetHashCode— pentru chei compuse înGroupBy, folosește întotdeauna tupluri(x.A, x.B), tipuri anonimenew { x.A, x.B }saurecord, deoarece acestea implementează automat egalitatea structurală.
Funcții și concepte înrudite
Any, All, Count și Sum: Evaluează condiții booleene rapide (cu scurtcircuitare) și calculează agregări numerice (Count, Sum, Average, Min, Max) peste colecții.Enumerable.Select: Proiectează (transformă) fiecare element al unei secvențe într-o formă nouă și aplatizează colecțiile imbricate cu SelectMany.Dictionary<TKey, TValue>: Stochează perechi cheie-valoare într-o tabelă de dispersie (hash table) cu căutare, inserare și ștergere în timp constant O(1).OrderBy / ThenBy: Sortează secvențele crescător sau descrescător pe baza unuia sau mai multor criterii și extrage pagini cu Skip și Take.