For - ForEach - List.ForEach performans karşılaştırması

Bir dizinin tüm elemanları üzerinde bir aksiyon gerçekleştirmemiz gerektiğinde, sıklıkla şu üç yoldan birini kullanırız;

  • For döngüsü
  • ForEach Döngüsü
  • List generic sınıfının ForEach extension method’u

Şimdi basit bir örnek ile bu üç yöntemi karşılaştıralım ()*;

( Not : Karşılaştırmalar; Windows7 64bit kurulu, Core2Duo 3.0 GHz ve 4 GB Ram’li bilgisayarımda yapılmıştır. Sadece fikir verme amaçlıdır, farklı durumlarda faklı sonuçlar ile karşılaşılabilir.)*

Öncelikle parametre olarak Generic List (List<T>) alan üç tane method yazalım;

private static long ToplamFor(List<int> Liste) { long Sonuc = 0; int ListeAdet = Liste.Count;

for (int iLoop = 0; iLoop &lt; ListeAdet; iLoop++)
    Sonuc += Liste[iLoop];

return Sonuc; }

private static long ToplamForEach(List<int> Liste) { long Sonuc = 0;

foreach (int Rakam in Liste)
    Sonuc += Rakam;

return Sonuc; }

private static long ToplamForEachExtension(List<int> Liste) { long Sonuc = 0;

Liste.ForEach(Rakam =&gt; Sonuc += Rakam);

return Sonuc; }</pre>

Aynı testi 10 defa gerçekleştirip, ortalamasını alacak bir test fonksiyonu yazalım. Yazacağımız fonksiyonu test listesinde olacak eleman adedini parametre olarak alacak;

private static void Testler(int ListeElemanAdet)
{
    List<int> ForSureler = new List<int>();
    List<int> ForEachSureler = new List<int>();
    List<int> ForEachExtensionSureler = new List<int>();

    List<int> TestVerisi = Enumerable.Range(0, ListeElemanAdet).ToList();

    Stopwatch sw = new Stopwatch();

    for (int iLoop = 0; iLoop < 10; iLoop++)
    {
        sw.Restart();
        ToplamFor(TestVerisi);
        sw.Stop();
        ForSureler.Add(sw.ElapsedTicks);

        sw.Restart();
        ToplamForEach(TestVerisi);
        sw.Stop();
        ForEachSureler.Add(sw.ElapsedTicks);

        sw.Restart();
        ToplamForEachExtension(TestVerisi);
        sw.Stop();
        ForEachExtensionSureler.Add(sw.ElapsedTicks);
    }

    Console.WriteLine("For Döngüsü ({0} Eleman) : {1}", ListeElemanAdet, ForSureler.Average());

    Console.WriteLine("ForEach Döngüsü ({0} Eleman) : {1}", ListeElemanAdet, ForEachSureler.Average());

    Console.WriteLine("ForEach Extension ({0} Eleman) : {1}", ListeElemanAdet, ForEachExtensionSureler.Average());
}

Artık uygulamamızın test fonksiyonunu kullanacak son kod parçasını yazabiliriz;

public static void Main(string[] args)
{
    Console.WriteLine("Test Başladı");

    Testler(1000);
    Testler(5000);
    Testler(10000);
    Testler(50000);
    Testler(100000);
    Testler(500000);
    Testler(1000000);
    Testler(5000000);
    Testler(10000000);
    Testler(50000000);

    Console.WriteLine("Test Bitti");

    Console.ReadLine();
}


Bakalım yaptığımız testler nasıl sonuç vermiş;

![For - ForEach - ForEach extension Performans Karşılaştırması / Ekran Görüntüsü](/assets/uploads/2010/10/For_ForEach_ForEachExtensionPerformansTest_0.png "For_ForEach_ForEachExtensionPerformansTest")

Sonuçlardan aşağıdaki tabloyu çıkarttım;
**Test Verisi** **For** **ForEach** **ForEach Extension**
*1.000* 71,1 121,5 79,7
*5.000* 34,3 92,2 55,6
*10.000* 70,0 185,1 110,4
*50.000* 349,3 918,4 568,3
*100.000* 715,2 1.902,7 1.159,0
*500.000* 3.583,3 9.379,3 5.600,0
*1.000.000* 7.260,4 18.877,9 11.242,8
*5.000.000* 37.927,2 96.096,9 57.845,4
*10.000.000* 74.553,5 192.621,6 115.559,6
*50.000.000* 371.698,1 956.394,4 572.776,7
İlk olarak **50.000 elemana** kadar olan listeler için **karşılaştırma** yapalım; ![For - ForEach - ForEach extension Performans Karşılaştırması / 50.000 elemana kadar inceleme](/assets/uploads/2010/10/For_ForEach_ForEachExtensionPerformansTest_1.png "For_ForEach_ForEachExtensionPerformansTest") Son olarak **50.000.000 elemana** kadar olan listeler için **karşılaştırma** yapalım; ![For - ForEach - ForEach extension Performans Karşılaştırması / 50.000.000 elemana kadar inceleme](/assets/uploads/2010/10/For_ForEach_ForEachExtensionPerformansTest_2.png "For_ForEach_ForEachExtensionPerformansTest")

Bu kodda ne yanlış var? – 7

Aşağıdaki kod sayesinde ekrana, listedeki isimleri küçük harflerle yazdırmak istiyorsunuz.

using System; using System.Collections.Generic;

public class EkranaYazdir { public static void Main() { List<string> Kisiler = new List<string>();

    Kisiler.Add("AHMET");
    Kisiler.Add("MEHMET");
    Kisiler.Add("AYŞE");
    Kisiler.Add("FATMA");

    /// string elemanları küçük harfe çevir
    Kisiler.ForEach(
        delegate(string k)
        {
            k = k.ToLower();
        }
    );

    /// console'a yaz
    Kisiler.ForEach(
        delegate(string s)
        {
            Console.WriteLine(s);
        }
    );
} }

MSDN‘de List<T>.ForEach() sayfasında;

Orjinali; Performs the specified action on each element of the List.

Türkçesi; Listedeki her eleman için belirlenmiş action çalıştırır.

yazısını okudunuz, ve kodun doğru çalışmasını bekliyorsunuz.

Fakat istediğiniz gibi çalışmıyor, sizce problem nedir ve nasıl düzeltilebilir?

Dosya uzantısını uygulamanız ile ilişkilendirin

Bir windows uygulaması geliştirdiniz ve uygulamanız belli uzantıdaki dosyalar üzerinde işlemler gerçekleştiriyor (Görüntüleme, Kaydetme, vs.)

Eğer ilgili uzantıdaki dosyaya çift tıklandığı zaman uygulamanızın açılmasını ve dosya üzerinde işlem yapmasını istiyorsanız, öncelikle dosya uzantısı ve uygulamanızı registry üzerinden birbiri ile ilişkilendirmelisiniz.

Aşağıdaki örnek kod sayesinde, eng uzantılı dosyaların uygulamanız ile ilişkilendirilmesini ve dosya ikonlarının sizin belirlediğiniz (icon.ico) olarak gözükmesini sağlayabilirsiniz;

Registry.ClassesRoot.CreateSubKey(“.eng”).SetValue(null, “EnginDosyasi.eng”);

RegistryKey rk = Registry.ClassesRoot.CreateSubKey(“EnginDosyasi.eng”); rk.CreateSubKey(“DefaultIcon”).SetValue(null, Application.StartupPath + “\icon.ico”); rk.CreateSubKey(@”shell\open\command”).SetValue(null, “"” + Application.ExecutablePath + “" "%1"”);</pre>

eng uzantılı bir dosyaya çift tıklandığında artık sizin uygulamanız açılacaktır.

Çift tıklandığı için uygulamanızı açtıran dosyaya, aşağıdaki kod satırı ile ulaşabilirsiniz;

public static void Main(string[] args)
{
    string Dosya = args[1];
}


Euler - 6

Euler serisinin altıncı yazısında, Project Euler’in 6. sorusunu çözeceğiz;

Orjinal Soru; The sum of the squares of the first ten natural numbers is, 12 + 22 + … + 102 = 385

The square of the sum of the first ten natural numbers is, (1 + 2 + … + 10)2 = 552 = 3025

Hence the difference between the sum of the squares of the first ten natural numbers and the square of the sum is 3025 - 385 = 2640.

Find the difference between the sum of the squares of the first one hundred natural numbers and the square of the sum.

Türkçesi; İlk 10 sayının karelerinin toplamı, 12 + 22 + … + 102 = 385

İlk 10 sayının toplamlarının karesi, (1 + 2 + … + 10)2 = 552 = 3025

İlk 10 sayı için toplamların karesi ile karelerin toplamı arasındaki fark; 3025 - 385 = 2640’tır.

İlk 100 sayının toplamların karesi ile karelerin toplamı arasındaki farkı bulunuz.

Önce siz çözmeyi deneyin, çözemezseniz ;

using System; using System.Linq;

public static class Program { public static void Main(string[] args) { Console.WriteLine(“Fark: {0}”, Math.Pow(Enumerable.Range(1, 100).Sum(), 2) - Enumerable.Range(1, 100).Select(i => i * i).Sum());

    Console.ReadLine();
} }

Nullable Tipler

Nullable tipler, ilgili tip‘in değer aralığına ve karakteristiğine sahip olmakla birlikte ek olarak null değer de içerebilen yapılardır.

Basit olarak, değişkenin değer içerip içermediği bilgisini saklar.

Nullable tipler, System.Nullable<T> türündedirler (T, değer tipi olmalıdır)

Unutmayın! Sadece değer tipleri (value type) nullable olabilir.

C# dili değer tipi listesi‘ne daha önce yazdığım makale veya MSDN üzerinden ulaşabilirsiniz.

C# dilinde, Nullable tipte değişkenler iki şekilde tanımlanabilir.

Birinci yöntemde, System.Nullable generic tipini ilgili değer tipi ile birlikte yazabiliriz;

System.Nullable<int> adet; System.Nullable<bool> sonuclandi;</pre>

İkinci yöntem, daha çok kullanılır ve daha kısa yazım şekline sahiptir. İlgili değer tipinin yanına soruişareti (?) karakteri koyarak yazılır;

int? adet;
bool? sonuclandi;

Bir nullable değişken, tanımlandığı anda null değerini içermez, sizin null eşitlemesini yapmanız beklenir;

int? adet = null;

Nullable tipteki bir değişkene değer ataması yapmak, normal bir değişkene değer ataması yapmak ile aynıdır.

adet = 100;

Nullable bir değişkenin değer içerip içermediğini anlamanın iki yolu vardır.

Birinci yöntemde, değişkenin null olup/olmadığı kontrol edilebilir.

if (adet != null)
{
    /// değeri var
}

Eğer değişken null değilse, değer içeriyor demektir.

İkinci yöntemde, değişkenin System.Nullable tipinden gelen sadece-okunabilir (read-only) HasValue özelliği kontrol edilir.

if (adet.HasValue)
{
    /// değeri var
}

Eğer değişken değer içeriyorsa, değeri okumak için, değişkenin System.Nullable tipinden gelen Value özelliği kullanılır.

Eğer değer içermeyen nullable bir değişkenin Value özelliğinden değer okumaya çalışırsanız, System.InvalidOperationException istisnası fırlatılır.

using System;

class NullableTipTest
{
    public static void Main()
    {
        int? adet = null;

        if (adet.HasValue)
            Console.WriteLine("adet değeri: " + adet.Value);
        else
            Console.WriteLine("adet değeri yok.");

        adet = 10;

        if (adet.HasValue)
            Console.WriteLine("adet değeri: " + adet.Value);
        else
            Console.WriteLine("adet değeri yok.");
    }
}


Yukarıdaki kodun çıktısı şöyle *olacaktır*;



>adet değeri yok.
adet değeri: 10



Engin Polat hakkında

Chief Architect, Microsoft RD, Microsoft MVP

Ada ve Ege'nin babası ;)

Kategoriler

İstatistik

Makale Adedi: 452

Creative Commons Lisansı