CodeGym /Kurslar /C# SELF /Siyahı: List<T>

Siyahı: List<T>

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

1. Giriş

Təsəvvür elə ki, alış-veriş siyahısı aparırsan. Bu gün 3 məhsul almalısan, sabah — 10, birisi gün isə cəmi bir dənə. Əgər massiv istifadə etsəydin, hər dəfə konkret məhsul sayına uyğun yeni massiv yaratmalı olardın. Ya da "birdən lazım olar" deyə çox böyük massiv yaradıb, bir sürü boş hüceyrə "daşımalı" olardın. Səmərəli səslənmir, düzdür?

İndi təsəvvür elə ki, sənin sehrli çantan var, ora nə qədər əşya qoysan, özü böyüyür, çıxarsan, kiçilir. Əvvəlcədən neçə əşya qoyacağını bilməyə ehtiyac yoxdur. Sadəcə qoyursan, çanta özü uyğunlaşır. Bax, proqramlaşdırmada C#-da List<T> məhz budur!

List<T> — müəyyən tipdə elementlər ardıcıllığını saxlamağa imkan verən ümumiləşdirilmiş kolleksiyadır. Əsas söz — "dinamik". Massivlərdən fərqli olaraq, List<T> proqram işləyərkən öz ölçüsünü dəyişə bilir. O, daxili tutumunu özü idarə edir, lazım olanda artırır.

List<T>-də T hərfi nə deməkdir? Bu, tip parametri adlanır. List yaradanda, T yerinə hansı tipdə məlumat saxlayacağını göstərirsən. Məsələn, List<int> yalnız tam ədədlər, List<string> yalnız sətirlər, List<double> isə yalnız onluq ədədlər saxlayacaq. Bu, təsadüfən portağal siyahısına alma əlavə etməyinə imkan vermir, kodunun sabitliyi və proqnozlaşdırılması üçün vacibdir.

Bunu niyə istifadə edirik?

Real layihələrdə çox vaxt əvvəlcədən neçə element olacağını bilmirsən. Məsələn:

  • Sayta daxil olan istifadəçilərin siyahısı.
  • Onlayn mağazanın səbətindəki məhsulların siyahısı.
  • Sorğuya görə axtarış nəticələrinin siyahısı.
  • Planlaşdırıcıda tapşırıqların siyahısı — indi məhz bunu hazırlayacağıq.

Bütün bu hallarda elementlərin sayı dəyişə bilər və List<T> bizim əvəzolunmaz köməkçimiz olur.

List<T>-in əsas metodları

Metod Təsviri Nümunə
Add(T item)
Siyahının sonuna element əlavə et
numbers.Add(5);
Insert(int idx, T)
Göstərilən mövqeyə əlavə et
numbers.Insert(0, 42);
Remove(T item)
Elementin ilk tapılanını sil
numbers.Remove(100);
RemoveAt(int idx)
Elementi indeksə görə sil
numbers.RemoveAt(2);
Clear()
Siyahını tam təmizlə
numbers.Clear();
Contains(T item)
Siyahıda element var, ya yox — yoxla
numbers.Contains(10);
IndexOf(T item)
Elementin ilk tapıldığı indeks
int pos = numbers.IndexOf(42);
Count
Siyahıdakı elementlərin sayı
int n = numbers.Count;
Capacity
Daxili buffer-in tutumu
numbers.Capacity = 100;

2. Siyahı (List<T>) yaratmaq

Keçək praktikaya! Təsəvvür elə ki, sadə tapşırıq meneceri yaratmaq qərarına gəlmişik. Bizə siyahı lazımdır ki, ora işlərimizi əlavə edək.

Yeni List<T> yaratmaq üçün new operatorundan istifadə edirik, digər obyektlərdə olduğu kimi.

List necə elan və yaradılır

Siyahı yaratmaq sintaksisi massivə bənzəyir, sadəcə kvadrat mötərizə yerinə kəskin mötərizə:

using System.Collections.Generic;

List<int> numbers = new List<int>();

Ətraflı bilmək istəyənlər üçün şərhlər:
- List<int> — tam ədədlər siyahısıdır (int). int yerinə istənilən tip yaza bilərsən: string, double, öz class-ın və s.
- Yaradandan sonra siyahı boşdur — uzunluğu 0-dır.

Nümunə: tətbiqimizin ilk addımı

Tutaq ki, tətbiqimizdə istifadəçi ad və yaş daxil edirdi (ilk dərslərdən yadındadır). İndi isə bir neçə ad saxlamaq üçün siyahı əlavə edək ki, sonra onlarla işləyə bilək.

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<string> names = new List<string>();

        Console.WriteLine("Üç ad daxil edin:");
        for (int i = 0; i < 3; i++)
        {
            string name = Console.ReadLine();
            names.Add(name);
        }

        Console.WriteLine("Daxil etdikləriniz:");
        foreach (string n in names)
        {
            Console.WriteLine(n);
        }
    }
}

Diqqət et Add()-ə. Məhz bu metod siyahıya yeni elementlər əlavə edir. Yəni — onu dinamik edir!

Siyahını dərhal elementlərlə yaratmaq olar!

List<string> planets = new List<string> { "Merkuri", "Venera", "Yer" };

Çox rahatdır, əgər "start heyəti" bilirsənsə. Bu sintaksis testlərdə və sabit məlumatların ilkinizasiya üçün tez-tez istifadə olunur.

3. List<T> ilə əsas əməliyyatlar

Hələ trüklərə keçməmiş, gəlin siyahının "əlifbasını" öyrənək.

Element əlavə etmək: Add()

Add() metodunu istifadə etmək — yeni əşyanı rəfə qoymaq kimidir:

List<int> numbers = new List<int>();
numbers.Add(42);
numbers.Add(100);

İndi içində: [42, 100]

Elementlərin sayını almaq: Count

Massivdən fərqli olaraq, siyahıda bu xüsusiyyət Length yox, Count adlanır:

int count = numbers.Count; // 2 qaytaracaq

Yadda saxla: siyahılarda Count istifadə olunur, massiv və sətirlərdə isə Length. Eyni məqsəd üçün fərqli xüsusiyyətlərdir.

Elementlərə indekslə müraciət

İki üsul var, mahiyyətcə eynidir:

int first = numbers[0]; // 42
numbers[1] = 200; // 100-ü 200 ilə əvəz etdik

Vacibdir: İndeksləmə, massivlərdə olduğu kimi, sıfırdan başlayır. Cəmi üç elementin varsa, numbers[3]-ə müraciət etmə!

Siyahı elementlərini dövr etmək

for və ya foreach dövründən istifadə edə bilərsən:

// for ilə — indeks lazımdırsa
for (int i = 0; i < numbers.Count; i++)
{
    Console.WriteLine(numbers[i]);
}

// foreach ilə — indeks lazım deyilsə
foreach (int number in numbers)
{
    Console.WriteLine(number);
}

foreach adətən daha rahat və başadüşüləndir, xüsusən böyük kolleksiyalarda.
Amma onunla kolleksiyanın elementlərini indekslə dəyişə və ya break ilə dövrü vaxtından əvvəl dayandıra bilməzsən, əlavə konstruksiyalar istifadə etməsən.

Elementi indeksə görə əlavə etmək: Insert()

Insert() metodu, əgər elementi siyahının sonuna yox, istənilən yerə əlavə etmək istəsən, istifadə olunur. Məsələn, ikinci yerə:

numbers.Insert(1, 55); // 55-i indeks 1-ə əlavə edəcək

İndi numbers: [42, 55, 200]

Elementləri silmək

Siyahıdan silmək əlavə etmək qədər asandır:

numbers.Remove(55); // 55-in İLK tapılanını siləcək
numbers.RemoveAt(0); // 0 indeksli elementi siləcək
numbers.Clear(); // Siyahını tam təmizləyir

Silinmənin nüansları:
- Remove ilə mövcud olmayan dəyəri silsən, heç nə baş verməyəcək: siyahı dəyişməyəcək, səhv almayacaqsan.
- Clear()-dan sonra siyahı yenə boşdur.

4. Faydalı nüanslar

List<T> necə böyüyür

List<T>-ə element əlavə edəndə, o, hər dəfə bir az böyümür. Əvəzində List<T> əvvəlcədən ehtiyatla yaddaş ayırır (daxili tutum — Capacity).

Elementlərin sayı tutumu keçəndə, siyahı daha böyük yaddaş bloku ayırır (adətən 2 dəfə böyük) və bütün köhnə dəyərləri ora köçürür:


Element əlavə edirik → yerləşdi → yerləşdi → yerləşdi →
Yeni element yerləşmir → böyük massiv yaradılır → məlumatlar köçürülür → davam edirik

Bu, elementləri daha tez əlavə etməyə imkan verir, çünki yaddaş hər Add-da yox, ara-sıra yenidən bölüşdürülür.

var list = new List<int>();    // Capacity = 0
list.Add(1);                   // Capacity = 4
list.Add(2);                   // Capacity = 4
list.Add(3);                   // Capacity = 4
list.Add(4);                   // Capacity = 4
list.Add(5);                   // Capacity = 8 (böyüdü!)

Capacity və Count: fərq nədir?

  • Count — siyahıya əlavə olunan elementlərin sayı.
  • Capacity — elementləri saxlayan daxili massiv ölçüsü.
List<int> nums = new List<int>();
Console.WriteLine(nums.Count); // 0
Console.WriteLine(nums.Capacity); // Adətən 0 və ya kiçik ölçü

nums.Add(123);
Console.WriteLine(nums.Count); // 1
Console.WriteLine(nums.Capacity); // İndi Count-dan çox ola bilər

nums.Capacity = 1000; // Əgər çox element olacaqsa, Capacity-ni əvvəlcədən artıra bilərsən

Əksər proqramçılar yalnız Count-dan istifadə edir, amma performansa həssas tətbiqlər yazırsansa (məsələn, oyunlar və ya data analizi), Capacity-ni incə tənzimləmək faydalı ola bilər.

5. Nümunə

Kiçik tətbiqimizi inkişaf etdiririk — indi istifadəçi sevdiyi ədədləri əlavə edə, sonra siyahı ilə işləyə: əlavə, silmək, göstərmək və təmizləmək.

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<int> favoriteNumbers = new List<int>();

        Console.WriteLine("Sevdiyiniz ədədləri daxil edin (hər sətrə bir dənə, 0 — bitir):");
        while (true)
        {
            int num = int.Parse(Console.ReadLine());
            if (num == 0) break;
            favoriteNumbers.Add(num);
        }

        Console.WriteLine("Sevdiyiniz ədədlər:");
        foreach (int n in favoriteNumbers)
        {
            Console.Write(n + " ");
        }

        Console.WriteLine("\nBirinci ədədi silmək istəyirsiniz? (y/n)");
        if (Console.ReadLine().ToLower() == "y")
        {
            favoriteNumbers.RemoveAt(0);
        }

        Console.WriteLine("İndi siyahınız:");
        foreach (int n in favoriteNumbers)
        {
            Console.Write(n + " ");
        }
    }
}

Qeyd: Burada int.Parse istifadə edirik. Real layihələrdə istifadəçi səhvlərinə görə proqramın "çöküb" getməməsi üçün həmişə int.TryParse ilə yoxlamaq daha yaxşıdır.

6. Başlanğıc üçün tipik səhvlər və "tələ"lər

Çox yayılmış ssenari: 0-dan List.Count-a qədər dövr yazırsan, amma dövr zamanı (məsələn, foreach-də) siyahını dəyişirsən (əlavə və ya silmə). Bunu etmə! Proqramçılar buna "dövr zamanı kolleksiyanı dəyişmək" deyir. Çox vaxt dərhal InvalidOperationException tipli istisna alırsan.

Pis kod nümunəsi:

foreach (int n in numbers)
{
    if (n < 0)
        numbers.Remove(n); // BUM! Runtime error.
}

Düzgün: ya silmək üçün indeksləri/elementləri ayrıca siyahıda topla, ya da for dövrünü tərsinə istifadə et.

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