CodeGym /Kurslar /C# SELF /Məlumatların filtrasiya olunması

Məlumatların filtrasiya olunması Where ilə

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

1. Giriş

Filtrasiya — bu, kolleksiyadan yalnız müəyyən şərtə cavab verən elementləri seçməkdir. Təsəvvür elə: bazanda 10 000 məhsul var, amma menecerə "sadəcə" 12 dənə lazımdır, hansı ki, yeni ağıllı kriteriyaya uyğundur. Hər dəfə əl ilə dövr yazıb, bir ton yoxlama etmək — heç də xoş deyil, üstəlik kod da oxunmaz olur. LINQ bu dərdi sənin yerinə həll edir.

Real tətbiqlərdə filtrasiya — məlumatlarla ən çox edilən əməliyyatdır: istifadəçiyə yalnız maraqlı olan qeydləri göstəririk, kolleksiyanı lazımsız elementlərdən "təmizləyirik", hesabat, axtarış və ya e-mail göndərişi üçün seçimlər edirik. Müsahibələrdə LINQ-filtrasiyası barədə suallar daim olur. Bu mövzunu başa düşmək — yeni başlayan .NET developer üçün uğurun açarıdır.

2. Where metodu ilə tanışlıq

Məna və iş prinsipi

Where metodu — bu, LINQ-un extension metodudur, hansı ki, filtrasiya şərtini müəyyən edən funksiya (və ya lambda expression) qəbul edir. O, yeni ardıcıllıq qaytarır (əsas kolleksiyanı dəyişmir!), hansı ki, yalnız şərt true qaytaran elementləri saxlayır.

Əsas signatura:

public static IEnumerable<TSource> Where<TSource>(
    this IEnumerable<TSource> source,
    Func<TSource, bool> predicate)

Generics və qorxulu sözlərdən qorxma. İndi əsas ideyanı başa düşmək vacibdir: Where əsas kolleksiyanı və sənin verdiyin şərti qəbul edir. Praktikada hər şey sadədir:

  • source — filtrlədiyimiz kolleksiya (məsələn, List<Product>)
  • predicate — funksiya/şərt (məsələn, p => p.Price > 100)

Sadə tapşırıq — başlamaq üçün

Tutaq ki, məhsullar siyahımız var və biz yalnız qiyməti 100-dən böyük olanları seçmək istəyirik. Köhnə dövrlərdə foreach dövrü yazıb, lazım olanları yeni siyahıya əlavə edərdik. LINQ bunu bir sətrə salır.

3. Filtrasiya

Bizim Product sinfi və başlanğıc kolleksiya

Keçən modulda təxminən belə bir məhsul sinfi yazmışdıq:


class Product
{
    public string Name { get; set; }
    public double Price { get; set; }

    // Ekrana gözəl çıxış üçün:
    public override string ToString()
    {
        return $"{Name} (qiymət: {Price})";
    }
}

Tutaq ki, məhsullar siyahımız var:


var products = new List<Product>
{
    new Product { Name = "Çörək", Price = 30 },
    new Product { Name = "Süd", Price = 87 },
    new Product { Name = "Pendir", Price = 250 },
    new Product { Name = "Şokolad", Price = 130 }
};

Where ilə 100-dən baha məhsulların filtrasiyası


var expensiveProducts = products.Where(p => p.Price > 100);

foreach (var product in expensiveProducts)
{
    Console.WriteLine(product);
}

Altda nə baş verir:

  • Where products siyahısındakı bütün elementləri bir-bir keçir,
  • Hər biri üçün funksiyanı çağırır (bizim halda: p => p.Price > 100),
  • Əgər funksiya true qaytarırsa, məhsul yeni kolleksiyaya düşür.

Ekranda nəticə:

Pendir (qiymət: 250)
Şokolad (qiymət: 130)

Diqqət et: əsas products siyahısı dəyişmir! LINQ sənin datanı pozmur.

4. Tənbəl filtrasiya (Deferred Execution)

Maraqlı və vacib məqam: Where nəticəsi yalnız sən həqiqətən elementlərə müraciət edəndə hesablanır. Məsələn, foreach dövrü başlayanda, LINQ əsas kolleksiyadan "keçir" və elementləri yerindəcə filtrləyir. Əgər nəticədən istifadə etmirsənsə, heç bir iş görülmür. Buna təxirə salınmış icra (deferred execution) deyilir.

Bu bizə bir ton üstünlük verir:

  • Çox uzun method zəncirləri qurmaq olar (məsələn, həm filtrlə, həm sort et), və yalnız ilk real nəticə sorğusunda hər şey icra olunur.
  • Yaddaşa qənaət: arada lazımsız kolleksiya çevrilmələri olmur.
  • Lazım olsa, icranı dayandırmaq və ya tapılan elementlərin sayına görə "kəsmək" olar.

Vizual sxem


Əsas kolleksiya       —►   Where (şərt)    —►   Yalnız lazım olan elementləri keçiririk
    
[ x ] [ x ] [ + ] [ + ]  —►   p.Price > 100      —►   [ + ] [ + ]

(x — şərtə uyğun gəlmir, + — uyğun gəlir)

5. Sintaksis variantları

Klassik extension method (Method Syntax)

Bu stili artıq istifadə edirik:

var result = products.Where(p => p.Price > 100);

Alternativ: Query Syntax

LINQ SQL sorğularına bənzər sintaksisi dəstəkləyir:


var result = from p in products
             where p.Price > 100
             select p;

Nəticə — eynidir!
Sintaksis seçimi — zövq məsələsidir, amma method syntax (nöqtə-metodlar) daha çox rast gəlinir, xüsusən real layihələrdə və uzun zəncirlər quranda.

6. Mürəkkəb filtrasiya şərtləri

Birkaç şərt

Məntiqi operatorlardan istifadə edə bilərsən (&&, ||, !):


// Bütün bahalı məhsulları tap, amma "Şokolad" istisna
var filtered = products.Where(
    p => p.Price > 100 && p.Name != "Şokolad"
);

Sətirə görə filtrasiya (alt sətir, register, Contains)


// Adında "l" hərfi olan məhsullar
var lProducts = products.Where(p => p.Name.Contains("l"));

Diqqət: Contains register-ə həssasdır! Əgər "case-insensitive" lazımdırsa, belə edə bilərsən:


var lProducts = products.Where(p => p.Name
    .ToLower().Contains("l")); // indi həm "Süd", həm də "Şokolad" seçiləcək

Birkaç kolleksiya üzrə filtrasiya

Tutaq ki, iki siyahın var — məhsullar və ödənişlər. Məhsulları filtrləmək olar, hansı ki, ödənişlər siyahısında var — amma bunun üçün AnyJoin metodlarından istifadə etmək daha yaxşıdır, bu barədə sonra danışacağıq. Sadəcə bil: LINQ daha mürəkkəb filtrasiyaları da bacarır!

7. Faydalı nüanslar

Daxili filtrasiya və method zəncirləri

Bir neçə filtrasiya mərhələsini birləşdirə bilərsən, Where bir neçə dəfə çağıraraq:


var filtered = products
    .Where(p => p.Price > 100)
    .Where(p => p.Name.StartsWith("Ş"));

Amma daha yaxşıdır ki, şərtləri bir Where-də məntiqi operatorlarla birləşdirəsən — həm daha effektiv, həm də kod daha sadə olur.

Daxili comparator-lar və custom funksiyalar

Bəzən standart operatorlar bəs etmir. Məsələn, sətirləri register-siz və mədəniyyətə uyğun filtrləmək lazımdır. Bu halda müqayisə metodlarından istifadə rahatdır:


var rusProducts = products.Where(
    p => p.Name.StartsWith("ş", StringComparison.OrdinalIgnoreCase)
);

8. Filtrasiya və istifadəçi daxilini işləmək

Gəlin sadə komanda filtrasiya nümunəsi edək! Məsələn, istifadəçidən minimum qiymət soruşaq, sonra uyğun məhsulları göstərək.


Console.Write("Məhsulun minimum qiyməti? ");
var minPriceStr = Console.ReadLine();
if (double.TryParse(minPriceStr, out double minPrice))
{
    var filtered = products.Where(p => p.Price >= minPrice);
    foreach (var product in filtered)
    {
        Console.WriteLine(product);
    }
}
else
{
    Console.WriteLine("Xəta: daxil edilən rəqəm deyil.");
}

İndi bizim "mini-tətbiq" artıq demək olar ki, mağaza kimidir!

9. Where istifadə edəndə tipik səhvlər və tələlər

Proqramlaşdırmada, həyatda olduğu kimi, gizli daşlar olur. Bax, nədən ehtiyatlı olmaq lazımdır.

ToList() və ya ToArray() çağırmağı unutmaq

Where nəticəsi — siyahıdır, nə də massiv! Bu, IEnumerable<Product> obyektidir. Əksər hallarda foreach dövründə əla işləyir, amma əgər sənə məhz kolleksiya lazımdırsa (məsələn, indekslə giriş planlaşdırırsansa), .ToList() və ya .ToArray() çağırmağı unutma:


var filteredList = products.Where(p => p.Price > 100).ToList();

Əgər bu məqamı unutsan, asanlıqla belə bir xəta ala bilərsən: "Kolleksiya dövr zamanı dəyişdirildi" — xüsusilə də, əgər dövr zamanı əsas kolleksiyanı dəyişmək qərarına gəlsən.

Əsas kolleksiyanı dəyişmək

Çünki LINQ-filtrasiyası təxirə salınmışdır, əgər dövrün ortasında əsas siyahıdan elementləri silirsənsə, istisna baş verə bilər. Xüsusilə bu, multi-thread hallarda və ya kolleksiya filtrasiyada dəyişəndə olur.

Null dəyərlər və predikatlar

Əgər kolleksiyada null varsa və sən predikatda obyektin sahəsinə yoxlamasız müraciət edirsənsə, NullReferenceException alacaqsan. Məsələn:


var filtered = products.Where(p => p.Name.StartsWith("A"));

Əgər products içində hansısa element null olsa, kod sınacaq.

Tövsiyə: əgər belə elementlər ola bilərsə, həmişə null yoxlaması əlavə et:


var filtered = products.Where(p => p != null && p.Name.StartsWith("A"));
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION