CodeGym /Kurslar /C# SELF /Aqreqat funksiyalar: Sum

Aqreqat funksiyalar: Sum, Count, Average, Max, Min

C# SELF
Səviyyə , Dərs
Mövcuddur

1. Giriş

Kolleksiyalarla işləyəndə tez-tez bizə lazım olur ki, təkcə hər elementə baxıb nəsə edək yox, həm də bütün məlumat dəstinə qısa bir "xülasə" alaq. Məsələn:

  • Neçə tələbənin beş aldığına baxmaq.
  • Məktəbdə ümumilikdə neçə şagird olduğunu öyrənmək.
  • Bütün tələbələrin imtahanda neçə bal topladığını hesablamaq.
  • Maksimum və minimum qiymətləri tapmaq.
  • Sinif üzrə orta balı hesablamaq.

Əlbəttə, bu tapşırıqları adi dövr (loop) və sayğac dəyişəni ilə həll etmək olar. Amma düzünü desək: belə elementar iş üçün iyirmi sətr kod yazmaq heç kimin ürəyincə deyil.

LINQ bizə aqreqat funksiyalar dəstini verir — hazır metodlar ki, kolleksiyanı götürür, bütün elementləri keçir və cavab verir: cəm, orta, maksimum, minimum və bəzən daha ağıllı şeylər.

Qısa "aqreqat cədvəli":

Metod Nə edir Nə qaytarır
Count()
Elementlərin sayını sayır
int
Sum()
Rəqəmsal dəyərlərin cəmini hesablayır Elementlərin tipindən asılıdır (
int
,
double
, ...)
Average()
Orta arifmetik hesablayır
double
və ya başqa rəqəmsal tip
Max()
Maksimum elementi tapır Kolleksiyanın elementi
Min()
Minimum elementi tapır Kolleksiyanın elementi

Bütün bu metodlar — IEnumerable<T> interfeysini reallaşdıran kolleksiyalar üçün extension-metodlardır. Ətraflı — LINQ aqreqat metodlarının rəsmi sənədləri.

2. Praktika üçün məlumatları hazırlayırıq

Gəlin tələbələrin qeydiyyatı üçün sadə bir tətbiqlə işləməyə davam edək. Bizdə belə bir class olsun:


// Tələbə modeli
public class Student
{
    public string Name { get; set; }
    public int Grade { get; set; } // Beş ballıq şkala üzrə qiymət
    public string Email { get; set; }
}

Və siyahı:


// Tələbələrin əsas siyahısı
List<Student> students = new List<Student>
{
    new Student { Name = "İvan", Grade = 5, Email = "ivan@example.com" },
    new Student { Name = "Olqa", Grade = 4, Email = "olga@example.com" },
    new Student { Name = "Artem", Grade = 3, Email = "artem@example.com" },
    new Student { Name = "Darya", Grade = 5, Email = "darya@example.com" },
    new Student { Name = "Petr", Grade = 2, Email = "petr@example.com" }
};

3. Elementlərin sayılması: Count()

Ən sadə statistika

Tutaq ki, sən bilmək istəyirsən neçə tələbən var:


int totalStudents = students.Count(); // 5
Console.WriteLine($"Ümumi tələbə sayı: {totalStudents}");

LINQ-sehr: Hər şey sadədir! Count() metodu kolleksiyadakı elementlərin sayını qaytarır.

Şərtlə saymaq

Bəs neçə əlaçı var?


int excellentStudents = students.Count(s => s.Grade == 5);
Console.WriteLine($"Beş alanlar: {excellentStudents}");

Burada Count-a lambda ötürürük — o, yalnız şərtə uyğun olanları qaytarır (s.Grade == 5). LINQ daxilində bu, Where(...).Count()-a bərabərdir, amma daha qısa və bir az daha effektiv işləyir.

Bəs kolleksiya boş olsa?

Əgər kolleksiya boşdursa, Count səmimi şəkildə 0 qaytaracaq — heç bir səhv olmayacaq.

4. Dəyərlərin cəmlənməsi: Sum()

Bütün qiymətlərin cəmini alırıq

Təsəvvür elə ki, sinifin topladığı ümumi balı bilmək istəyirsən:


int sumOfGrades = students.Sum(s => s.Grade); // 5+4+3+5+2 = 19
Console.WriteLine($"Bütün qiymətlərin cəmi: {sumOfGrades}");

Sum selector (lambda ifadəsi) qəbul edir, hansı ki, hər element üçün dəyəri qaytarır.

Sadəcə rəqəmlər kolleksiyası üçün cəmləmə

Səndə sadəcə rəqəmlər siyahısı varsa, selector lazım deyil:


int[] numbers = { 1, 2, 3, 4, 5 };
int sum = numbers.Sum(); // 15

Tipik səhvlər və nüanslar

Əgər kolleksiya boşdursa, Sum() rəqəmsal tiplər üçün 0 qaytaracaq. Amma əgər kolleksiya nullable tiplərdən ibarətdirsə (int?, double?), Sum da düzgün işləyir: null dəyərləri saymır.

5. Orta arifmetik: Average()

Sinifdə orta balı hesablayırıq

Klassik sual: tələbə orta neçə bal alıb?


double averageGrade = students.Average(s => s.Grade); // (5+4+3+5+2)/5 = 3.8
Console.WriteLine($"Orta bal: {averageGrade:F2}");

Average — statistikada çox faydalı dostdur. Diqqət et: qaytarılan dəyər həmişə double-dır, hətta ilkin dəyərlər int olsa belə. Bu, onluq hissənin "kəsilməsinin" qarşısını alır.

Heç bir element yoxdursa

Əgər ilkin kolleksiya boşdursa, Average() çağırışı InvalidOperationException atacaq. Bu, çox yayılmış tələyə çevrilir: əgər kolleksiyada nəsə olduğuna əmin deyilsənsə, əvvəlcədən yoxla!


if (students.Any())
    Console.WriteLine(students.Average(s => s.Grade));
else
    Console.WriteLine("Orta balı hesablamaq üçün məlumat yoxdur!");

Rəqəmsal massiv üzrə orta dəyər


double avg = numbers.Average();

6. Maksimum və minimum: Max()Min()

Kim sinifin ulduzudur, kim isə "zirzəmidə"

Bilmək istəyirsən kim sinifi qiymətləri ilə "daşıyır", kim isə... müəllimi narahat edir? Asan:


int maxGrade = students.Max(s => s.Grade); // 5
int minGrade = students.Min(s => s.Grade); // 2

Console.WriteLine($"Maksimum qiymət: {maxGrade}");
Console.WriteLine($"Minimum qiymət: {minGrade}");

Bəs bu qəhrəman kimdir?

Bəzən təkcə rəqəm yox, həm də bu dəyəri alan tələbənin adı vacib olur. Ən yüksək qiymət alan tələbəni tapırıq:


// Azalan sıralamadan sonra ilk əlaçını götürürük
var bestStudent = students.OrderByDescending(s => s.Grade).First();
Console.WriteLine($"Ən yaxşı tələbə: {bestStudent.Name} ({bestStudent.Grade})");

.NET-in yeni versiyalarında MaxBy da var, bu işi daha gözəl görməyə imkan verir. .NET 6-dan mövcuddur, .NET 9-da isə daha rahat olub (bax: MaxBy Microsoft Docs-da). Amma MaxBy olmasa belə, sıralama və .First() ilə rahat keçinmək olar.

Tələlər və fərqlər

Əgər kolleksiya boşdursa, Max()Min() çağırışı da InvalidOperationException atacaq. Ona görə buna hazır ol (xüsusən əvvəlcədən kolleksiyanı yoxlamamısansa):


if (students.Any())
    Console.WriteLine($"Maksimum qiymət: {students.Max(s => s.Grade)}");
else
    Console.WriteLine("Maksimum tapmaq üçün tələbə yoxdur.");

7. Aqreqat metodların "zənciri" nümunələri

Çox vaxt aqreqat metodlar filtrasiya və proyeksiya ilə birlikdə istifadə olunur:


// Beş alanlar arasında orta bal
double avgExcellent = students
    .Where(s => s.Grade == 5)
    .Average(s => s.Grade); // həmişə 5, amma nümunə üçün yaxşıdır

// Qiyməti 4 və yuxarı olan tələbələrin bal cəmi
int sumGood = students
    .Where(s => s.Grade >= 4)
    .Sum(s => s.Grade);

// Unikal emaillərin sayı (birdən lazım olar)
int uniqueEmails = students
    .Select(s => s.Email)
    .Distinct()
    .Count();

Burada LINQ "tam gücü ilə işləyir": sadə əməliyyatların birləşməsi ilə ifadəli və oxunaqlı kod yazmaq olur, hətta pişiyin belə başa düşər (əgər pişik Junior C# Developer-disə).

8. "Əl ilə" yanaşma ilə müqayisə: niyə aqreqat istifadə edək?

Anlamaq üçün gəlin LINQ-i adi dövrlə müqayisə edək, məsələn, orta balı hesablamaq üçün:

Adi yanaşma:


int sum = 0;
int count = 0;
foreach (var s in students)
{
    sum += s.Grade;
    count++;
}
double average = (count != 0) ? (double)sum / count : 0;

LINQ:


double average = students.Average(s => s.Grade);

Boş kolleksiyanı yoxlamaq da daha asandır!

9. Faydalı nüanslar

Qısa şəkildə performans və reallaşdırma xüsusiyyətləri

LINQ-aqreqatları, əksər LINQ əməliyyatlarından fərqli olaraq, dəqiq icra olunur! Yəni sən Sum(), Count(), Average(), Max(), Min() çağıranda, kolleksiya üzərində bütün keçid artıq həmin anda baş verir. Bu metodlar kolleksiya yox, yekun nəticə qaytarır.

Bu vacibdir: əgər aqreqatdan əvvəl nəsə ağır bir şey etmisənsə, məsələn, mürəkkəb filtrasiya və ya çevirmə — o, yalnız aqreqat çağıranda bir dəfə icra olunacaq.

Aqreqat metodlar query-syntax dəstəkləyirmi?

LINQ-metodlarını işə salmazdan əvvəl tez-tez soruşurlar: "Bütün bunları query-syntax ilə yazmaq olar?" Qısa cavab: query-syntax özü aqreqatlar üçün açar sözlər vermir, amma method syntax ilə qarışdırmaq olar:


var avg = (from s in students where s.Grade > 3 select s.Grade).Average();

Mötərizədə adi query-syntax, sonra isə aqreqat metodu çağırılır. Bu, düşündüyündən daha çox istifadə olunur!

10. LINQ istifadə edərkən tipik səhvlər

Səhv №1: Average(), Max() və ya Min() boş kolleksiyaya tətbiq etmək cəhdi.
Əgər kolleksiya boşdursa, Sum()Count() rahatlıqla 0 qaytaracaq, amma Average(), Max()Min() istisna atacaq. Bu metodları çağırmazdan əvvəl kolleksiyada ən azı bir element olduğuna əmin ol.

Səhv №2: Yanlış imzalı lambda ötürmək.
Məsələn, aqreqat funksiyaya (Sum, Max və s.) rəqəm əvəzinə string ötürsən, kompilyasiya səhvi alacaqsan. Xüsusilə anonim metodlardan istifadə edəndə asanlıqla səhv etmək olur.

Səhv №3: Elementlərin sayını yoxlamaqda optimal olmayan üsul.
Where(...).Count() metodu əvvəlcə yeni kolleksiya yaradır, sonra elementləri sayır. Bunun əvəzinə Count(predicate) istifadə et — o, dərhal uyğun elementlərin sayını sayır və daha sürətli işləyir.

Səhv №4: Aqreqasiyada nullable tiplərin xüsusiyyətlərini nəzərə almamaq.
Əgər int? üzrə cəm hesablayırsansa, Sum() null dəyərləri saymayacaq. Bu, düzgün davranışdır, amma bəzən əvvəlcədən nəzərə almasan, gözlənilməz nəticə verə bilər.

Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION