Date Image Saturday, November 27, 2010 | Kategoriler | C#, Tümü

SortedList Ve SortedSet Koleksiyonları

Koleksiyonların listelenmesi bir çok uygulama tarafından kullanılabilir. Bu koleksiyon içerisinde string, integer, object ya da custom bir class bulunabilir. Bir koleksiyonun sıralanarak listelenmesi istendiğinde bir çok yol kullanılabilir. Bir döngü içerisinde tüm öğeler birbirleriyle karşılaştırılarak sıraları değiştirilebilir.

Bu makalenin konusu elbette sıralama algoritmaları değil. Burada .Net Framework içerisinde bulunan “SortedList” ve “SortedSet” koleksiyonlarından bahsedeceğiz. Bu koleksiyonlar ile ilgili bazı temel bilgileri anlamaya çalışacağız.
Öncelikle bilinen değişken türleri ile koleksiyonlar oluşturup nasıl sıralama yapıldığına bakacağız. Daha sonra custom bir sınıf hazırlayarak bu sınıfın tipinde değişkenlerle oluşturacağımız koleksiyonların davranışlarına bakacağız.Burada kullanacağımız koleksiyonlar generic koleksiyonlar olacaktır.

Başlangıç olarak, SortedList koleksiyonuna değinelim. System.Collections.Generic namespace i altında bulunur. ICollection, IEnumerable, IDictionary ve ICloneable interface lerinden türemiştir. Burada dikkat edilmesi gereken şey, SortedList in IDictionary interface inden türemiş olmasıdır. IDictionary interface inden türemiş olması nedeniyle içerdiği nesnelerin, bir Key ve bir Value değerine sahip olmak zorundadır.

Yukarıda bahsettiğim gibi, bir SortedList oluştururken öncelikle Key ve Value tipleri belirtilmelidir. Key, koleksiyon içerisindeki elemanı temsil eden değerdir. Value ise Key ile temsil edilen elemanın içerdiği değerdir. Yani koleksiyon içerisindeki bir elemanı Key property si ile bularak içerdiği değeri de Value property si ile elde edebiliriz.

SortedList koleksiyonunda sıralama, Key değerine göre yapılmaktadır. Asıl elde edilmek istenen değer Value iken ve bu değere göre sıralama yapılması gerekir iken Key property sinin içerdiği değere göre sıralama yapması size biraz garip gelebilir. Ancak şöyle bir örnek seneryodan yola çıkar isek biraz daha aklımıza yatabilir diye düşünüyorum :

Bir text dosyasında müşterilerimizin id ve ad-soyad bilgisini tutuyar diye düşünürsek, bu senaryoda Key bilgisi id, Value bilgisi de ad-soyad olabilir. Bu şekilde müşterilerin id numaralarına göre sıralama yapabiliriz. Bir diğer sıralama da ad-soyad alanına göre yapılabilir; bu kez de Key ad-soyad, Value ise id olabilir, bu şekilde ad-soyad alanına göre sıralama yapılabilir.
Uygulama olarak bir örnek yapalım :

private static void WriteSortedListMember()
        {
            SortedList<intstring> sortedList = new SortedList<intstring>();
 
            sortedList.Add(0,"N");
            sortedList.Add(1, "F");
            sortedList.Add(2, "A");
            sortedList.Add(3, "A");
            sortedList.Add(4, "H");
 
            WriteMembersOfSortedList(sortedList);
        }

 
        private static void WriteMembersOfSortedList(SortedList<intstring> list)
        {
            foreach (KeyValuePair<intstring> member in list)
            {
                Console.WriteLine("Key : {0}\tValue : {1}", member.Key, member.Value);
            }
        }

 

WriteSortedListMember metodunda Key tipi integer, Value tipi ise string olan bir SortedList koleksiyonu oluşturduk ve sırası ile Key ve Value değerlerine sahip elemanlar ekledik.Burada dikkat edersek SortedList in Add metodu bizden Key ve Value değerlerini istemektedir ve tipleri ise koleksiyonu tanımlarken belirttiğimiz tiplerdir.



Oluşturduğumuz koleksiyonun listelenmesini istersek alacağımız sonucu görelim

static void Main(string[] args)
        {
            Console.WriteLine("### SortedList Öğeleri ###");
            WriteSortedListMember();
 
            Console.ReadKey();
        }



Görüldüğü üzere sıralama Key değerlerine göre yapıldı. Eğer ekleme sırasında değişiklik olmadan Value değerlerine göre bir sıralama yapılmasını istersek :

private static void WriteSortedListMember()         
{             
            SortedList<intstring> sortedList = new SortedList<intstring>(); 
            sortedList.Add(4, "N");
            sortedList.Add(2, "F");
            sortedList.Add(0, "A");
            sortedList.Add(1, "A");
            sortedList.Add(3, "H");
            WriteMembersOfSortedList(sortedList);        
 }

WriteSortedListMember metodunu bu şekilde değiştirmeliyiz. Key değerleri Value değerlerinin doğru sıralanmasını sağlayacak şekilde olmalıdır. Ya da Key ve Value değerlerinin yerleri değiştirilmelidir. Bu şekilde sonuç aşağıdaki gibi olacaktır :



Görüldüğü üzere sıralama yine Key değerlerine göre yapıldı ancak, Key değerlerinin karşılığındaki Value değerlerinin yerleri değiştirilmiş olduğundan sıralama doğru oldu.

Burada dikkat edilmesi gereken bir başka nokta da Value değeri olarak aynı değerlerin girilmesine izin verildiğidir. Ancak bir SortedList koleksiyonunda aynı değere sahip birden fazla Key değeri olamaz. Buna karşılık Value değerlerinde bir sınırlama yoktur.
Şimdi de inceleyeceğimiz bir diğer koleksiyonumuz olan ”SortedSet” e geçelim. SortedSet koleksiyonu .Net Framework 4.0 ile gelen bir koleksiyon olmakla beraber yine içerdiği elemanları sıralı olarak döndürmektedir.

SortedSet de SortedList gibi System.Collections.Generic namespace i altında bulunmaktadır. Türediği interface ler ise ; ISet<T>, ICollection, ICollection<T>, IEnumerable, IEnumerable<T>, ISerializable, IDeserializationCallback interfaceleridir.



SortedSet in SortedList ten ilk farkı IDictionary interface ini implemente etmemesidir. Bu nedenle Key-Value nitelikleri yoktur. ISet interface inden türemiştir ve bu interface de ICollection ve IEnumerable interface lerinden türediğinden bunların özelliklerine sahiptir. Bununla birdikte Add metodunda koleksiyonun tipinden bir değer almaktadır.



Aynı zamanda Add metodu boolean tipinde bir geri dönüş değerine sahiptir. Bu şu anlama gelmektedir ; Add metodunun aldığı parametre yani listeye eklenmek istenen eleman, liste içerisinde bulunan herhangi bir eleman ile aynı değerde ise geriye false döner ve ekleme işlemini yapmaz, eğer listede bulunmayan unique bir eleman eklenmek istenirse true döner ve ekleme işlemini yapar. Dönüş değerini dikkate almayabiliriz, yanlızca kullanıcıdan anlık değerler istiyorsak eklemek istediği değerin daha önceden eklendiği yanıtını gösterebiliriz.
SortedList örneği üzerine devam ederek SortedSet örneğimizi ekleyelim :

private static void WriteSortedSetMember()
        {
            SortedSet<string> sortedSet = new SortedSet<string>();
 
            sortedSet.Add("F");
            sortedSet.Add("A");
            sortedSet.Add("N");
            sortedSet.Add("A");
            sortedSet.Add("H");
 
            WriteListMembers(sortedSet);
        }

 

private static void WriteListMembers(IEnumerable list)
        {
            foreach (var member in list)
            {
                Console.WriteLine(member);
            }
        }

SortedSet koleksiyonumuza eklediğmiz değeri listeleyelim.

static void Main(string[] args)
        {
            Console.WriteLine("### SortedList Öğeleri ###");
            WriteSortedListMember();
            Console.WriteLine();

            Console.WriteLine("### SortedSet Öğeleri ###");
            WriteSortedSetMember();
 
            Console.ReadKey();
        }

 



Görüldüğü üzere sıralama doğru bir şekilde yapıldı. Dikkat edilecek nokta ise SortedSet koleksiyonumuza “A” değerini 2 kez eklememize rağmen listelediğimizde sadece tek bir A değerinin görünmesi. Bunun nedeni az önce bahsettiğimiz Add metodunun işleyişidir. 2. kez “A” değerini eklemeye çalıştığımızda Add metodu false değeri döndürerek elamnın eklenmesini durdurdu. Bu yönüyle SortedSet, HashSet<T> koleksiyonuna benzemektedir.

SortedSet koleksiyonuna şimdiye kadar sadece bilinen değişken türlerinden elemanlar ekledik. Eğer custom bir class hazırlayarak bu türden bir eleman eklersek ne olacak. Şimdi bunu deneyelim.
Bunun için ListMember adında bir class oluşturalım :

public class ListMember

    {
        public int Id { getset; }
        public string Content { getset; }
        public DateTime Time { getset; }
 
        public override string ToString()
        {
            return Content;
        }
    }

ListMember class ımızı oluşturduk şimdi de SortedSet koleksiyonumuza bu tipteki elemanlarımızı ekleyerek, liste elemanlarını ekranda göstermeye çalışalım.

private static void WriteSortedSetMemberWithClass()
        {
            SortedSet<ListMember> sortedSet = new SortedSet<ListMember>();
 
            sortedSet.Add(new ListMember { Id = 12, Content = "F", Time = DateTime.Now.AddMinutes(12) });
            sortedSet.Add(new ListMember { Id = 10, Content = "A", Time = DateTime.Now.AddMinutes(10) });
            sortedSet.Add(new ListMember { Id = 17, Content = "N", Time = DateTime.Now.AddMinutes(17) });
            sortedSet.Add(new ListMember { Id = 1, Content = "A", Time = DateTime.Now.AddMinutes(1) });
            sortedSet.Add(new ListMember { Id = 8, Content = "H", Time = DateTime.Now.AddMinutes(8) });
 
            WriteListMembers(sortedSet);
        }

Yine aynı sıralama değerlerine sahip elemanlar oluşturduk. Ancak bu sefer hazırladığımız ListMember class ının Content property sinin değeri oldular. Bu şekilde eklediğimiz elamanları listeleyelim ve sıralamayı görelim.

static void Main(string[] args)
        {
            Console.WriteLine("### SortedList Öğeleri ###");
            WriteSortedListMember();
            Console.WriteLine();
            Console.WriteLine("### SortedSet Öğeleri ###");
            WriteSortedSetMember();
            Console.WriteLine();
            Console.WriteLine("### ListMember İçerikli SortedSet Öğeleri ###");
            WriteSortedSetMemberWithClass();
 
            Console.ReadKey();
        }



ListMember tipindeki elemanları içeren SortedSet koleysiyonumuzun elemanları listelemek istediğimizde yukarıdaki hata ile karşılaştık. Bu hatanın nedeni , koleksiyon içerisindeki ListMember tipindeki elemanların sıralama kriterinin bilinmemesidir. Bir string değere sahip elemanlarda sorun olmaz iken ListMember class ının birden fazla property içermesi ve bunlardan hangisinin sıralama için kullanılacağının bilinmemesi bu hatayı meydana getirmiştir. Burada çözüm ListMember classının SortedSet için sıralama kriteri şu property dir demek değildir. Çözüm ListMember class ının IComparable interface inden türeterek CompareTo metodunu implemente etmektir. CompareTo metodundan dönen integer değere göre SortedSet koleksiyonu bir sıralama yapacak ve elemanları listelenecektir.
Bu işlem için yapılması gerekenler ile birlikte ListMember class ı :

public class ListMember : IComparable<ListMember>
    {
        public int Id { getset; }
        public string Content { getset; }
        public DateTime Time { getset; }
 
        public override string ToString()
        {
            return Content;
        }
 
        #region IComparable<ListMember> Members
 
        public int CompareTo(ListMember other)
        {
            CaseInsensitiveComparer coparer = new CaseInsensitiveComparer();
 
            return coparer.Compare(this.Content,other.Content);
        }
 
        #endregion
    }

CompareTo metodu 2 ListMember değeri arasında karşılaştırma yapmaktadır. Karşılaştırma kriteri ise Content property sidir. Burada Id ya da Time property si ile de karşılaştırma yapılabilir ve sıralamayı bı değerler üzerinden yapmasını sağlayabiliriz.
Bu değişiklikleri yaptıktan sonra listelemeye çalıştığımızda :



Yukarıdaki sonucu alıyoruz ve bu olması gereken sıralamadır. Yani herşey yolunda ve makalenin de sonu gelmiş demektir.