MySQL Java JavaScript PHP Python HTML-CSS C-sharp

Gruparea datelor

Pentru gruparea datelor după anumite criterii se utilizează operatorul group by și metoda GroupBy().

Operatorul group by

Să presupunem că avem un set de obiecte de tipul următor:

record class Person(string Name, string Company);

Această clasă reprezintă un utilizator și are două proprietăți: Name (numele utilizatorului) și Company (compania unde lucrează utilizatorul). Să grupăm setul de utilizatori după companie:

Person[] people =
{
   new Person("Tom", "Microsoft"), new Person("Sam", "Google"),
   new Person("Bob", "JetBrains"), new Person("Mike", "Microsoft"),
   new Person("Kate", "JetBrains"), new Person("Alice", "Microsoft"),
};

var companies = from person in people
               group person by person.Company;

foreach (var company in companies)
{
   Console.WriteLine(company.Key);

   foreach (var person in company)
   {
       Console.WriteLine(person.Name);
   }
   Console.WriteLine(); // pentru separarea între grupuri
}

Dacă în expresia LINQ ultimul operator care efectuează operațiuni asupra selecției este group, atunci operatorul select nu se folosește.

Operatorul group primește criteriul după care se face gruparea:

group person by person.Company

În acest caz, gruparea se face după proprietatea Company. Rezultatul operatorului group este o selecție care constă din grupuri. Fiecare grup reprezintă un obiect IGrouping<K, V>, unde K indică tipul cheii - tipul proprietății după care se face gruparea (aici este de tip string). Iar V reprezintă tipul obiectelor grupate - în acest caz grupăm obiecte de tip Person.

Fiecare grup are o cheie, pe care o putem obține prin proprietatea Key: g.Key. Aici va fi numele companiei.

Toate elementele din grup pot fi obținute printr-o iterație suplimentară. Elementele grupului au același tip ca și tipul obiectelor care au fost transmise operatorului group, adică în acest caz obiecte de tip Person.

Rezultatul afișării:

Microsoft
Tom
Mike
Alice

Google
Sam

JetBrains
Bob
Kate

Metoda GroupBy

Ca alternativă, se poate folosi metoda de extensie GroupBy. Aceasta are mai multe suprascrieri, să luăm cea mai simplă dintre ele:

GroupBy<TSource, TKey>(Func<TSource, TKey> keySelector);

Această versiune primește un delegat care, ca parametru, primește fiecare element al colecției și returnează criteriul de grupare.

Rescriem exemplul anterior folosind metoda GroupBy:

Person[] people =
{
   new Person("Tom", "Microsoft"), new Person("Sam", "Google"),
   new Person("Bob", "JetBrains"), new Person("Mike", "Microsoft"),
   new Person("Kate", "JetBrains"), new Person("Alice", "Microsoft"),
};

var companies = people.GroupBy(p => p.Company);

foreach (var company in companies)
{
   Console.WriteLine(company.Key);

   foreach (var person in company)
   {
       Console.WriteLine(person.Name);
   }
   Console.WriteLine(); // pentru separarea între grupuri
}

Crearea unui nou obiect în timpul grupării

Să modificăm interogarea și să creăm un nou obiect din grup:

Person[] people =
{
   new Person("Tom", "Microsoft"), new Person("Sam", "Google"),
   new Person("Bob", "JetBrains"), new Person("Mike", "Microsoft"),
   new Person("Kate", "JetBrains"), new Person("Alice", "Microsoft"),
};

var companies = from person in people
               group person by person.Company into g
               select new { Name = g.Key, Count = g.Count() };

foreach (var company in companies)
{
   Console.WriteLine($"{company.Name} : {company.Count}");
}

Expresia:

group person by person.Company into g

definește variabila g, care va conține grupul. Cu ajutorul acestei variabile putem apoi crea un nou obiect de tip anonim (deși putem defini o nouă clasă pentru această sarcină):

select new { Name = g.Key, Count = g.Count() }

Acum, rezultatul interogării LINQ va reprezenta un set de obiecte de tip anonim, cu două proprietăți Name și Count.

Rezultatul programului:

Microsoft : 3
Google : 1
JetBrains : 2

O operație similară folosind metoda GroupBy:

var companies = people
               .GroupBy(p => p.Company)
               .Select(g => new { Name = g.Key, Count = g.Count() });

Interogări imbricate

De asemenea, putem realiza interogări imbricate:

Person[] people =
{
   new Person("Tom", "Microsoft"), new Person("Sam", "Google"),
   new Person("Bob", "JetBrains"), new Person("Mike", "Microsoft"),
   new Person("Kate", "JetBrains"), new Person("Alice", "Microsoft"),
};

var companies = from person in people
               group person by person.Company into g
               select new
               {
                   Name = g.Key,
                   Count = g.Count(),
                   Employees = from p in g select p
               };

foreach (var company in companies)
{
   Console.WriteLine($"{company.Name} : {company.Count}");
   foreach (var employee in company.Employees)
   {
       Console.WriteLine(employee.Name);
   }
   Console.WriteLine(); // pentru separarea între grupuri
}

Aici, proprietatea Employees a fiecărui grup este formată cu ajutorul unei interogări suplimentare care selectează toți utilizatorii din acel grup. Rezultatul afișării:

Microsoft : 3
Tom
Mike
Alice

Google : 1
Sam

JetBrains : 2
Bob
Kate

O interogare similară folosind metoda GroupBy:

var companies = people
               .GroupBy(p => p.Company)
               .Select(g => new
               {
                   Name = g.Key,
                   Count = g.Count(),
                   Employees = g.Select(p => p)
               });
← Lecția anterioară Lecția următoare →