CodeGym /Kurslar /C# SELF /Kolleksiyaların sıralanması

Kolleksiyaların sıralanması

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

1. Giriş

Əgər sənin heç vaxt corab dolabın olubsa və orada cüt tapmağa çalışmısansa, artıq sıralama problemini yaşamısan. Hər şey qarışıq olanda, lazım olan şeyi tapmaq əsl questə çevrilir. Proqramlaşdırmada kolleksiyalarla da eyni vəziyyətdir.

Sıralama — bu, kolleksiyadakı elementləri müəyyən bir kriteriyaya görə (məsələn, əlifba, dəyər, tarix və s.) düzülüşdürmək prosesidir. Bu vacibdir:

  • İstifadəçiyə məlumatları göstərmək üçün (heç kim xaosu sevmir).
  • Axtarışı asanlaşdırmaq üçün (məsələn, binary search ancaq sıralanmış kolleksiyalarda işləyir).
  • Müqayisə, hesabat, export və digər əməliyyatlar üçün.

Milyonluq sual: "Əgər məndə cəmi beş element varsa, sıralamağa ehtiyac yoxdur?" — Teorik olaraq, bəli, amma beş beş yüzə və ya beş minə çevriləndə, avtomatlaşdırma olmadan keçinmək olmur.

.NET-də sıralama üçün iki əsas yanaşma var:

  • Orijinal kolleksiyanı dəyişmək (məsələn, List<T>-i Sort metodu ilə sıralamaq).
  • Kolleksiyanın yeni sıralanmış kopyasını yaratmaq (məsələn, massiv klonlamaq, sonra sıralamaq).

.Sort() metodu ilə listlərin sıralanması

Sort() metodu List<T> sinfində var, çünki bu sinif IList<T> interfeysini implement edir və indekslə giriş və elementlərin sırasını dəyişmək imkanı verir.

Nümunə — ədədlərin artan sırada sıralanması:


using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        var numbers = new List<int> { 5, 2, 9, 1, 5, 6 };
        numbers.Sort();
        Console.WriteLine("Artan sırada sıralama:");
        foreach(var number in numbers)
        {
            Console.Write($"{number} "); // 1 2 5 5 6 9
        }
    }
}

Burada "yerində" sıralama gedir: orijinal numbers listi dəyişir, elementlər yerini dəyişir.

Sətirlərin sıralanması

Sıralama sətirlər üçün də əla işləyir:


var words = new List<string> { "apelsin", "alma", "banan", "armud" };
words.Sort();
Console.WriteLine(string.Join(", ", words)); // apelsin, armud, banan, alma

Maraqlı fakt: default olaraq sətir sıralaması Unicode qaydasına görə gedir, "insan" əlifbasına görə yox (xüsusilə fərqli dillər üçün, çoxdilli tətbiqlərdə bunu nəzərə al).

2. Öz qaydalarına görə sıralama

Bəzən "default" sıralama uyğun olmur. Tutaq ki, istifadəçiləri ada görə yox, yaşa və ya qeydiyyat tarixinə görə sıralamaq istəyirsən.

Lambda ifadəsi ilə sıralama (Sort(Comparison<T>) metodu)

Sort metodunu elə çağırmaq olar ki, xüsusi sıralama qaydası — iki elementin müqayisə funksiyasını ötürəsən.

İstifadəçiləri yaşa görə sıralamaq:


class User
{
    public string Name { get; set; }
    public int Age { get; set; }
}

// ...

var users = new List<User>
{
    new User { Name = "Alisa", Age = 30 },
    new User { Name = "Bob", Age = 25 },
    new User { Name = "Eva", Age = 35 }
};

users.Sort((u1, u2) => u1.Age.CompareTo(u2.Age));

foreach (var user in users)
{
    Console.WriteLine($"{user.Name}: {user.Age}");
}
// Çıxış:
// Bob: 25
// Alisa: 30
// Eva: 35

Bu magiya necə işləyir? (u1, u2) => u1.Age.CompareTo(u2.Age) lambda-sı mənfi qaytarırsa, u1 daha cavan, müsbət — daha yaşlı, 0 — yaşlar bərabərdir.

IComparer<T> interfeysindən istifadə

Bəzən sıralama qaydasını ayrıca sinfə çıxarmaq istəyirsən, məsələn, çox kolleksiyan və ya mürəkkəb məntiqin varsa.


class UserAgeComparer : IComparer<User>
{
    public int Compare(User x, User y)
    {
        return x.Age.CompareTo(y.Age);
    }
}

// ...

var users = new List<User>{ /* ... */ };
users.Sort(new UserAgeComparer()); // indi yaşa görə sıralanır

Bu rahatdır, əgər proqramın müxtəlif yerlərində sıralama lazımdırsa və ya bir neçə fərqli qayda varsa.

Bir neçə sahə üzrə əl ilə sıralama

Əgər bəzi istifadəçilərin yaşı eynidirsə, amma həmin yaş qrupunda onları ada görə sıralamaq istəyirsənsə:


users.Sort((u1, u2) => {
    int ageCompare = u1.Age.CompareTo(u2.Age);
    if (ageCompare != 0)
        return ageCompare;
    else
        return u1.Name.CompareTo(u2.Name);
});

İndi əvvəlcə yaşa, sonra ada görə sıralanır.

3. Kolleksiyanın kopyasını sıralamaq (orijinalı dəyişmədən)

Əgər orijinal listi dəyişmək istəmirsənsə, sıralamadan əvvəl onu kopyala:


var copy = new List<int>(numbers);
copy.Sort();

Custom obyektlər üçün də eyni:


var usersCopy = new List<User>(users);
usersCopy.Sort((a, b) => a.Age.CompareTo(b.Age));

4. Massivlərin sıralanması

Massivlərlə (T[]) də hər şey sadədir:


int[] numbers = { 4, 2, 9, 7 };
Array.Sort(numbers); // orijinal massiv dəyişir

"Custom" sıralama üçün:


Array.Sort(numbers, (a, b) => b.CompareTo(a)); // azalan sırada sıralama

Diqqət et, Array.Sort orijinal massivi dəyişir, yeni massiv qaytarmır. Əgər orijinalı saxlamaq lazımdırsa, əvvəlcədən kopyala:


int[] oldNumbers = { 3, 2, 1 };
int[] copy = (int[])oldNumbers.Clone();
Array.Sort(copy);

5. Dictionary-lərin "sıralanması" (Dictionary<TKey, TValue>)

Dictionary<TKey, TValue> — mahiyyətcə sırasız kolleksiyadır (yəni, iterasiya zamanı qayda zəmanət verilmir). Amma bəzən "sıralanmış cütlər" almaq istəyirsən.

Sıralanmış açar və ya dəyərlər almaq üçün, cütləri listə kopyala və istədiyin kimi sıralama apar:


var dict = new Dictionary<string, int>
{
    { "alma", 2 },
    { "apelsin", 5 },
    { "armud", 3 }
};

// Açar üzrə sıralama:
var keyValueList = new List<KeyValuePair<string, int>>(dict);
keyValueList.Sort((a, b) => a.Key.CompareTo(b.Key));
foreach (var kv in keyValueList)
{
    Console.WriteLine($"{kv.Key}: {kv.Value}");
}

// Dəyər üzrə sıralama:
keyValueList.Sort((a, b) => a.Value.CompareTo(b.Value));
foreach (var kv in keyValueList)
{
    Console.WriteLine($"{kv.Key}: {kv.Value}");
}

Əgər sıralanmış açar və ya dəyərlər listi lazımdırsa:


var sortedKeys = new List<string>(dict.Keys);
sortedKeys.Sort();

var sortedValues = new List<int>(dict.Values);
sortedValues.Sort();

Amma unutma ki, Dictionary strukturu dəyişmir — sadəcə sıralanmış iterasiya alırsan. .NET 9-da OrderedDictionary<TKey, TValue> olacaq, hansı ki, elementlərin sırasını saxlayır. Tez-tez yox, amma bəzən belə struktur lazım olur.

6. Faydalı nüanslar

Müqayisə interfeysini implement etmək mütləqdir?

Sadə: əgər obyektlərin "özləri" necə müqayisə olunacağını "bilsin" istəyirsənsə (məsələn, tarixə və ya ada görə), IComparable<T> interfeysini implement et.


class Product : IComparable<Product>
{
    public string Name { get; set; }
    public decimal Price { get; set; }

    public int CompareTo(Product other)
    {
        return Price.CompareTo(other.Price);
    }
}

İndi belə edə bilərsən:


var products = new List<Product> { /* ... */ };
products.Sort(); // qiymətə görə sıralayır

Əgər default müqayisə uyğun deyilsə — IComparer<T> istifadə et və ya yuxarıda göstərildiyi kimi lambda ötür.

İstifadəçi siyahısını əlifba sırası ilə sıralamaq

Tutaq ki, tətbiqdə istifadəçi siyahısı var:


List<string> users = new List<string> { "Viktor", "Anna", "Ekaterina", "Boris" };
users.Sort(); // indi users sıralanıb: Anna, Boris, Viktor, Ekaterina

Tapşırıqları təciliyə görə sıralamaq


class Task
{
    public string Title { get; set; }
    public int Priority { get; set; } // 1 - təcili, 2 - vacib, 3 - gözləyə bilər
}

var todo = new List<Task>
{
    new Task { Title = "Ev tapşırığını et", Priority = 2 },
    new Task { Title = "Çörək al", Priority = 1 },
    new Task { Title = "Seriala bax", Priority = 3 }
};

todo.Sort((a, b) => a.Priority.CompareTo(b.Priority));

foreach (var task in todo)
    Console.WriteLine($"{task.Priority}: {task.Title}");

Sıralama üsullarının müqayisəsi

Kolleksiya Yerində dəyişir? Sıralama metodu Qayda vermək olar?
List<T>
Bəli
Sort()
Bəli: lambda və ya IComparer
T[]
Bəli
Array.Sort()
Bəli: lambda və ya IComparer
Dictionary<TKey, TValue>
Xeyr — (list yaradıb sıralayırıq) Bəli: lambda və ya IComparer ilə

7. Tipik səhvlər və sıralama nüansları

Yerində sıralama — orijinal kolleksiyanı dəyişir! Əgər orijinal məlumat dəyişməməlidirsə — əvvəlcədən kopyala.

Dəyişməz kolleksiyanı sıralamağa cəhd (məsələn, ReadOnlyCollection<T>) runtime səhvinə gətirib çıxaracaq.

Sətirlərin müxtəlif mədəniyyətlərdə fərqli sıralanması: sətir sıralaması (xüsusilə kiril, umlaut və s.) müxtəlif lokalizasiya üçün fərqli ola bilər. Düzgün sıralama üçün Comparer.Create(...) istifadə et və lazımi mədəniyyəti seç.

Dictionary-lərin sıralanması strukturunu dəyişmir — həmişə yeni cütlər ardıcıllığı (və ya yeni list) qaytarılır.

Mürəkkəb qayda üçün öz məntiqinlə IComparer<T> interfeysindən istifadə et.

Səhv sıralama nümunəsi (praktik "tələ" kimi):


var numbers = new List<int> { 1, 2, 3 };
var sorted = numbers.Sort(); // SƏHV: Sort() void qaytarır!

Düzgün:


numbers.Sort(); // yerində numbers dəyişir

// Əgər yeni kolleksiya lazımdırsa:
var sorted = new List<int>(numbers);
sorted.Sort();
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION