1. string tipli massiv
Qısaca olaraq, string tipli massiv haqqında danışmaq istəyirəm.
Artıq dediyimiz kimi, massiv istənilən tipdə ola bilər. Yəni, string tipli massiv də yarada bilərik. Gəlin baxaq, əgər bizə belə bir proqram yazmaq lazım olsaydı ki, “klaviaturadan 10 sətir daxil edir və onları əks ardıcıllıqla ekrana çıxarır”, kod necə olardı:
string[] array = new string[10]; // 10 elementlik massiv-obyekt yaradırıq
for (int i = 0; i < 10; i++) // 0-dan 9-a qədər dövr
{
array[i] = Console.ReadLine(); // Klaviaturadan sətir oxuyuruq və massivə yazırıq
}
for (int i = 9; i >= 0; i--) // 9-dan 0-a qədər dövr
{
Console.WriteLine(array[i]); // Massivin növbəti elementini ekrana çıxarırıq
}
Kod demək olar ki, dəyişməyib! Sadəcə massiv yaradanda int tipini string ilə əvəz etdik. Qalan hər şey tam eynidir!
2. string tipli massiv yaddaşda
Bir faydalı fakt da var. 3 şəkilə baxaq:
Şəkil 1. string obyekti yaddaşda necə yerləşir:
Diqqət et, sətirin mətni birbaşa dəyişəndə saxlanmır: onun üçün ayrıca yaddaş bloku ayrılır. string tipli dəyişəndə isə mətn obyektinin ünvanı (referansı) saxlanılır.
Şəkil 2. Tam ədədlər massivinin yaddaşda yerləşməsi:
Bu şəkli də artıq görmüsən.
Şəkil 3. Yaddaşda string massiv necə yerləşir:
Solda string[] tipli massiv-dəyişəni görürük (massiv-obyektin ünvanını saxlayır).
Ortada — string tipli massiv-obyekt.
Sağda isə — mətn saxlayan string-obyektlər.
string tipli massiv-obyektin hüceyrələrində mətnlər (string-lər) yox, onların ünvanları (referansları) saxlanılır. Eynilə string tipli dəyişənlərdə də mətnin ünvanı saxlanılır.
3. C#-da massivlərin tez initialize olunması
Massivlər — çox faydalı şeydir, ona görə də C# developer-ləri onlarla işi maksimum rahat etməyə çalışıblar. Və ilk etdikləri şey — massivin initialize olunmasını sadələşdirmək olub, yəni ilkin dəyərləri ora yazmaq.
Çox vaxt, proqramın haradansa oxuduğu datalardan əlavə, ona öz daxili dataları da lazımdır. Məsələn, bütün ayların uzunluğunu massivdə saxlamaq lazımdır. Bu kod necə görünə bilər:
int[] months = new int[12];
months[0] = 31; // yanvar
months[1] = 28; // fevral
months[2] = 31; // mart
months[3] = 30; // aprel
months[4] = 31; // may
months[5] = 30; // iyun
months[6] = 31; // iyul
months[7] = 31; // avqust
months[8] = 30; // sentyabr
months[9] = 31; // oktyabr
months[10] = 30; // noyabr
months[11] = 31; // dekabr
Amma bunu daha qısa yazmaq olar — C# yaradıcılarına təşəkkür:
// ilin aylarının uzunluqları
int[] months = new int[] { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
Sadəcə bütün massiv elementlərini vergüllə ayırıb yaza bilərsən!
Rahatdır, düzdür? Amma hələ bu da hamısı deyil.
Məlum olur ki, compiler massiv-dəyişənin tipinə baxıb massiv-obyektin tipini özü müəyyən edə bilir. Uzunluğunu isə — sadəcə mötərizədə neçə element varsa, sayır.
Ona görə bu kodu daha da qısa yaza bilərsən:
// ilin aylarının uzunluqları
int[] months = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
Əla deyil? 🙂
Bu yazılışa “massivin tez initialize olunması” deyirlər. Bu, təkcə int üçün yox, başqa tiplər üçün də işləyir...
// ilin aylarının adları
string[] months = { "Yanvar", "Fevral", "Mart", "Aprel", "May", "Iyun", "Iyul", "Avqust", "Sentyabr", "Oktyabr", "Noyabr", "Dekabr"};
4. foreach dövrü
Massivin bütün elementlərini gəzmək o qədər tez-tez lazım olur ki, bunun üçün ayrıca dövr icad ediblər(!). Onun adı foreach-dir. Yazılışı belədir:
foreach (int score in scores)
{
Console.WriteLine($"Ballar: {score}");
}
Burada dövr özü elementləri gəzib keçir ― heç bir əl ilə indeks yoxdur. Elementləri birbaşa dəyişmək olmaz (dövr daxilində onlar yalnız oxumaq üçün açıqdır), amma sadəcə “gəzib keçmək” üçün çox rahatdır.
Compiler foreach dövrünü aşağıdakı koda çevirəcək:
for (int i = 0; i < scores.Length; i++)
{
int score = scores[i];
Console.WriteLine($"Ballar: {score}");
}
Yəni heç bir magiya yoxdur. İndi başa düşmək asandır ki, niyə score dəyişəni ilə massiv elementlərini dəyişə bilmirsən.
Gəlin bir nümunə də yazaq: bütün balların cəmini tapaq.
int sum = 0;
foreach (int score in scores)
{
sum += score;
}
Console.WriteLine($"Bütün balların cəmi: {sum}");
Hansını nə vaxt istifadə etməli?
- Əgər indeks lazımdırsa və ya elementləri dəyişmək istəyirsənsə — for dövrü.
- Sadəcə dəyərləri gəzmək üçün — foreach daha tez və təmizdir.
5. Sondan indeksləşdirmə: ^ operatoru
Artıq C#-da massivdən elementləri sondan almaq olur. Əvvəllər necə idi, sonuncu elementi almaq üçün belə yazırdın:
int lastScore = scores[scores.Length - 1];
İndi isə hər şey daha rahatdır. Sadəcə indeksdən əvvəl ^ yazırsan və sayma sondan başlayır:
int lastScore = scores[^1]; // Sonuncu element
int penultimate = scores[^2]; // Sonuncudan əvvəlki element
- ^1 — sondan birinci (yəni sonuncu).
- ^2 — sondan ikinci.
Vizualizasiya
| İndeks | scores massivindəki dəyər | Adi indeks | Sondan indeks |
|---|---|---|---|
| 0 | 10 | 0 | ^5 |
| 1 | 15 | 1 | ^4 |
| 2 | 8 | 2 | ^3 |
| 3 | 22 | 3 | ^2 |
| 4 | 17 | 4 | ^1 |
score[^1] = 17, score[^2] = 22 — rahat və aydındır.
Vacib! Diqqət et, sondan indekslər 1-dən başlayır, 0-dan yox.
6. Diapazonlar: .. (range) operatoru
Bəzən əsas massivdən alt-massiv almaq lazımdır. C#-da bunun üçün xüsusi diapazon operatoru .. var — bu, massivdən istədiyin “parçanı” almaq üçün qısa və rahat üsuldur.
Belə alt-massivə bəzən slice (ingiliscə “slice”) deyirlər və o, iki sərhədlə müəyyən olunur: başlanğıc və son.
Vacib məqam: sağ sərhəd nəticəyə daxil olmur!
Necə görünür
int[] scores = { 10, 15, 8, 22, 17 };
int[] top3 = scores[0..3]; // 0-dan 2-yə qədər elementlər: {10, 15, 8}
- scores[0..3] — 0-cı indeksdən (daxil olmaqla) 3-cü indeksə (DAHİL OLMADAN) qədər elementləri alırıq.
- Nəticə massivdə 0, 1 və 2 indeksli elementlər olacaq.
Qısaltmalar
Əgər sol sərhəd göstərilməyibsə, ən başdan başlayırıq:
int[] firstTwo = scores[..2]; // scores[0..2] ilə eyni, yəni {10, 15}
Əgər sağ sərhəd göstərilməyibsə, sona qədər alırıq:
int[] fromThird = scores[2..]; // {8, 22, 17}
Mənfi indekslər
^ simvolu ilə sondan indeksləri saymaq olar:
int[] lastTwo = scores[^2..]; // {22, 17}
Burada ^2 — “sondan ikinci element” deməkdir.
Həmçinin, hər iki tərəfdə mənfi indekslərdən istifadə edərək “aralıq” diapazon da götürmək olar:
int[] mid = scores[1..^1]; // {15, 8, 22} (2-ci elementdən sonuncudan əvvəlkinə qədər)
Nələri yadda saxlamaq lazımdır
- Sağ sərhəd həmişə daxil olmur — yəni a..b yazanda, a-dan b-1-ə qədər bütün elementləri alırsan.
- Əgər sərhədlər massivdən kənara çıxsa, IndexOutOfRangeException atılacaq.
- Slice — yeni massivdir, orijinal dəyişmir. Yeni massivdə etdiyin dəyişikliklər əsas massivə təsir etmir.
Praktik nümunələr
int[] arr = { 1, 2, 3, 4, 5, 6, 7 };
int[] arr = { 1, 2, 3, 4, 5, 6, 7 };
int[] start = arr[..3]; // {1, 2, 3}
int[] end = arr[^2..]; // {6, 7}
int[] middle = arr[2..5]; // {3, 4, 5}
int[] all = arr[..]; // {1, 2, 3, 4, 5, 6, 7} (tam surət)
GO TO FULL VERSION