1. Ağrının təkamülü
Yəqin ki, belə bir şeylə rastlaşmısan: sadəcə kolleksiyadan keçmək yox, həm də hər bir elementin nömrəsini bilmək lazımdır. Məsələn, nömrələnmiş siyahı çıxarmaq, sıfır olmayan indeksli elementləri dəyişmək və ya hər üçüncü elementlə nəsə etmək üçün. Adi for ilə — asandır:
// Hər şey klassik, C#-ın klasiği:
for (int i = 0; i < list.Count; i++)
{
Console.WriteLine($"{i}: {list[i]}");
}
Amma LINQ yazmağa başlayanda birdən... indeks itir! O gözəl .Where, .Select, .OrderBy — bunlar sənə elementin özünü verir, amma nömrəsini yox. Əlbəttə, belə etmək istərdin:
list.SelectWithIndex((item, index) => ...);
Amma SelectWithIndex kimi standart metod heç vaxt olmayıb. Düzdür, Select-in overload-u ilə indeksi almaq olur, amma... indeksi transformasiya/proyeksiya etmədən istifadə etmək istəyəndə əlavə .Select yazmalı olurdun, bu da LINQ kodunu bir az qarışıq və az oxunaqlı edirdi.
.NET 9-dan əvvəl necə sağ qalırdıq
Köhnə vaxtlarda C# proqramçıları öz hiyləgər trüklərini tapırdılar:
var result = list.Select((item, index) => new { item, index });
Bir də başqa LINQ metodları ilə kombinasiyalar, amma heç vaxt "daxili" hiss olunmurdu, istədiyin kimi gözəl olmurdu.
2. Yeni LINQ metodu: Index — nədir və niyə lazımdır?
Rəsmi təsviri
.NET 9-da developer komandası minlərlə proqramçının (yaxşı, Twitter-də on minlərlə, bu da az deyil) səsini eşitdi və LINQ-a yeni extension-metod — Index əlavə etdi. Rəsmi .NET 9 sənədində belə yazılıb:
Index() ardıcıllığın hər bir elementinə sıfırdan başlayaraq sıra nömrəsi əlavə edir və (dəyər, indeks) cütlüyü qaytarır, anonim obyektlər yaratmağa və ya .Select((item, idx) => new { item, idx }) yazmağa ehtiyac olmadan.
Bu, güclüdür — indi Index sadəcə hər element üçün sənə cütlük verir: elementin özü və onun indeksi.
Metodun signaturası
public static IEnumerable<(T Element, int Index)> Index<T>(this IEnumerable<T> source);
Sadə dillə: Kolleksiyadakı hər element üçün sən xüsusi "tuple" alırsan — Element və onun Index. Vəssalam. Artıq anonim tiplər düzəltməyə ehtiyac yoxdur.
3. Index metodunun istifadə nümunələri
Çox sadə nümunə
Gəlin sevimli meyvələr siyahısı götürək.
var fruits = new List<string> { "Alma", "Banan", "Portağal", "Kivi" };
foreach (var (fruit, idx) in fruits.Index())
{
Console.WriteLine($"{idx}: {fruit}");
}
Nəticə:
0: Alma
1: Banan
2: Portağal
3: Kivi
Bax belə! İndi sən rahatlıqla "indeks-dəyər" cütlüyü alıb istənilən LINQ sorğusunda istifadə edə bilərsən.
LINQ-un digər metodları ilə inteqrasiya
Index — LINQ ailəsinin tam hüquqlu üzvüdür! Onu rahatlıqla "zəncirə" əlavə edə bilərsən.
Nümunə 1: İndeksi tək olan elementləri filtrləmək
var numbers = Enumerable.Range(10, 10); // 10, 11, ... 19
var oddIndexes = numbers.Index()
.Where(pair => pair.Index % 2 == 1)
.Select(pair => pair.Element);
Console.WriteLine(string.Join(", ", oddIndexes));
Nəticə:
11, 13, 15, 17, 19
Nümunə 2: İndeksi cüt olan elementləri dəyişmək
var users = new List<string> { "Anna", "İqor", "Katyə", "Denis" };
var modified = users.Index()
.Select(pair => pair.Index % 2 == 0 ? pair.Element.ToUpper() : pair.Element.ToLower());
foreach (var name in modified)
Console.WriteLine(name);
Nəticə:
ANNA
iqor
KATYƏ
denis
Nümunə 3: İndeks üzrə digər kolleksiyalarla birləşdirmək (zip-ə bənzər)
var ids = new[] { 101, 102, 103 };
var names = new[] { "Alice", "Bob", "Charlie" };
var merged = names.Index()
.Join(ids.Index(),
namePair => namePair.Index,
idPair => idPair.Index,
(namePair, idPair) => (idPair.Element, namePair.Element));
foreach (var (id, name) in merged)
Console.WriteLine($"{id}: {name}");
Nəticə:
101: Alice
102: Bob
103: Charlie
4. Index real tətbiqdə
Gəlin bizim "əbədi" tədris tətbiqimizə yeni funksiya əlavə edək: bütün tələbələri kolleksiyadan sıra nömrəsi ilə çıxaraq (məsələn, istifadəçi tələbəni nömrə ilə seçə bilsin deyə).
Nümunə: Tələbələrin siyahısını nömrə ilə çıxarmaq
Güman edək ki, artıq Student sinfi var:
public class Student
{
public string Name { get; set; }
public int Grade { get; set; }
}
Kiçik tələbə siyahısı yaradaq:
var students = new List<Student>
{
new Student { Name = "Daşa", Grade = 5 },
new Student { Name = "Petya", Grade = 3 },
new Student { Name = "Vova", Grade = 4 },
new Student { Name = "Olya", Grade = 5 }
};
İndi Index ilə hamısını nömrə ilə gözəl çıxarırıq:
foreach (var (student, idx) in students.Index())
{
Console.WriteLine($"{idx + 1}. {student.Name} — Qiymət: {student.Grade}");
}
Burada
idx + 1 — indeksləmə adətə uyğun olaraq bir-dən başlayır, sıfırdan yox.
Nəticə:
1. Daşa — Qiymət: 5
2. Petya — Qiymət: 3
3. Vova — Qiymət: 4
4. Olya — Qiymət: 5
Praktiki fayda: İndi istifadəçi tələbəni nömrə ilə seçmək istəsə — hər şey hazırdır! Kod sadələşdi, "əl ilə" sayğaclar yoxdur, maksimum oxunaqlılıq — minimum bug.
5. Müqayisə: Index köhnə yanaşmalardan nə ilə yaxşıdır?
.NET 9-dan əvvəl: köhnə stil
Əvvəllər element və indeksini birlikdə almaq üçün .Select((item, index) => ...) overload-u və anonim tiplərdən istifadə edirdik:
var withIndexes = students.Select((student, index) => new { student, index });
Lazım olan sahələri almaq üçün daim .student, .index yazmalı idin — üstəlik tip anonimdir, gözəl adlandırılmış tuple yoxdur.
.NET 9 ilə: XXI əsr stili
İndi — sahələr, anonim tiplər barədə düşünməyə ehtiyac yoxdur. Hər şey şəffafdır:
foreach (var (student, idx) in students.Index())
{
// qutudan çıxan kimi işləyir, intuitiv, sadə, gözəl
}
Kod daha təmiz oldu. Daha az kod, daha az səhv. Böyük LINQ zəncirləri üçün idealdır, əlavə overload-lar barədə düşünmək istəmirsən.
6. İncəliklər və istifadə xüsusiyyətləri
Tətbiq sahəsi
Index IEnumerable<T> interfeysini implement edən istənilən obyektlə işləyir. Yəni — bütün adi kolleksiyalar, massivlər, digər LINQ sorğularının nəticələri ilə.
Index hansı tip qaytarır?
O, tuple-lar siyahısı qaytarır, birinci element — obyektin özü (Element adlanır), ikinci — Index (int tipi). Müasir C# tuple sintaksisi sayəsində birbaşa dövrdə foreach (var (element, index) in ...) yazıb hər ikisini dəyişənlərə ala bilərik.
Query Syntax ilə istifadə etmək olar?
Yox, Index extension-metoddur, query syntax (SQL-ə bənzər LINQ) onu birbaşa dəstəkləmir. Yəni belə işləməyəcək:
// İşləmir!
var query = from s in students.Index() select ...;
Birləşdirmək istəsən, sadəcə metodu mötərizəyə al və nəticə ilə adi kolleksiya kimi işləyin:
var query = from pair in students.Index()
where pair.Index > 1
select pair.Element;
İndeksləmə: həmişə sıfırdan
Index həmişə sıfırdan başlayır, C#-da əksər şeylər kimi. Bir-dən başlamaq lazımdırsa — lazım olan yerdə +1 əlavə et.
8. Səhvlər və xüsusiyyətlər — nələrə diqqət etmək lazımdır
Bir çox tələbə əvvəlcə Index və .Select((item, index) => ...) overload-u arasında çaşır. Ən çox rast gəlinən səhvlər:
— Index-i query syntax-da istifadə etməyə çalışırlar: "Niyə işləmir?" — çünki o, yalnız extension-metod kimi işləyir.
— Gözləyirlər ki, indeks 1-dən başlasın, amma təbii ki, 0-dan başlayır.
— Fikirləşirlər ki, Index orijinal kolleksiyanı dəyişir — amma bütün LINQ metodları kimi, o, yeni ardıcıllıq qaytarır, orijinalı dəyişmir (immutable yanaşma).
Bir maraqlı xüsusiyyət də var: əgər kolleksiya "tənbəl"dirsə (yəni LINQ sorğuları default olaraq tənbəldir), Index də indeksləri elementlərə müraciət etdikcə hesablayacaq, əvvəlcədən yox. Bu, böyük və ya hətta sonsuz ardıcıllıqlarla işləmək üçün əladır — indeksləmə həmişə düzgün olacaq və RAM-ı "partlatmayacaq".
GO TO FULL VERSION