erhaba arkadaşlar, yeni başlayan kod sever uykusuzlarıda düşünerek foreach yapısını olabildiğince sade ve birazda irdeleyerek anlatmaya çalışacağım. Bilen arkadaşlar için anlatım biraz uzun ve basit gelebilir, umarım çok sıkmadan konuyu tamamlayabilirim. O bakımdan hızlıca bir giriş yapıp tanım yerine daha verimli olduğunu düşündüğüm “doğma sebebi”ni inceleyerek konuya başlamak istiyorum. Yani hangi sebepten ihtiyaç duyulmuşta bu yapı oluşturulmuş. Bu sorunun iki cevabı var. Birincisi henüz testlerini yapmadığım performansla ilgili, o yüzden hakkında şimdilik pek bilgi veremeyeceğim. Bilen veya araştıran arkadaşlar aşağıda paylaşılarsa, bu alana seve seve eklerim. Diğeri ise temel amaçlardan biri olan kolaylık. Bu nedenleri incelemeden önce foreach hakkında aşağıdaki kod yapısı ile biraz fikir edinelim;
1 2 3 4 5 6 7 |
static void Main(string[] args){ int[] sayilar = { 1, 2, 3, 4, 5}; foreach (int sayi in sayilar) { Console.Write(sayi); } Console.ReadKey(); } |
Yukarıda “sayilar” adında 5 elemanlı bir dizi oluşturdum ve “sayilar” dizisinin her bir elemanını hafızaya tek tek getirebilmesi için foreach yapısında “int sayi” değişkenini tanımladım. Aslında İngilizce konuşma dili olan bu yapı bize zaten ne yapmak istediğini “sayi in sayilar” yani “sayilar içindeki sayi” diyerek ifade ediyor. Ayrıca değişkenlere (sayi, sayilar) çok takılmayın, okunabilrliği kolay olması açısından dizi için “sayilar”, elemanları tek tek hafızada tutacak değişken içinde “sayi” adlandırmasını tercih ettim. Burada gözden kaçan bir nokta var sanki, benim aklıma bir soru geldi mesela; elemanları tek tek hafızada tutacak değişken ne demek? Böyle koca koca odaları varda döngü boyunca hepsini bir yerde mi tutacak yoksa her döngüde diğerini yok edip yenisinimi hanesine yazacak? Burada ikinci şık sorunun cevabı oluyor. foreach her döndüğünde “sayi” değişkenine sıradaki değeri yazıyor. Buraya kadar gelmişken son değerden sonra ne oluyor onuda kısaca konuşalım, son değere ulaşıca bu değeri “sayi” adlı değişkene taşıyarak yapı içindeki işlemlere tabi tutup sonra ise döngüden çıkıyor. Ve bildiğiniz üzere bir alt satırdan devap ediyor, e tabi bir yanlışımız olmaz ise. Alan Perlis’in de dediği gibi:
Hatasız program yazmanın iki yolu vardır, yalnızca üçüncü yol çalışır.
Özlü sözümüzüde söylediğimize göre foreach yapısının davranış şeklini bir toparlayalım;
-
foreach yapısı;
- Bir “dizi” veya “koleksiyon” içerisindeki eleman sayısı kadar döngü yapar,
- Her bir döngüde, üzerinde çalıştığı yığının (dizi, koleksiyon) elemanlarından bir tanesini sıraya uygun olarak (hafızaya) getirir,
- Bu getirdiği elemanı foreach yapısı oluşturulurken tanımlanan değişkene (2. satırdaki “int sayi” gibi) atar,
- Böylece gruptan ayrılmış ve tek başına kalmış bu elemanları kendi döngüsünde istediğimiz yönde (aritmetik işlemler, sayaç, vb.) kullanabiliriz.
Ayrıca bazı arkadaşlar dikkat etmiştir, burada bir yaşam döngüsüde mevcut. Yeni başlayan arkadaşlar bunu ilk defa duymuş olabilirler, bu konudan hemen sonra araştıracak bir konunuz daha oldu affola :)
Şimdi bu yapı bize nasıl bir kolaylık sağlıyor ona bakalım, yani bu yapıya neden ihtiyaç duyulmuş inceleyelim. Bunun için kodlama zaman çizgisinde biraz geriye gideceğiz ama çok az. Sanki kullanılmıyormuş gibi konuştum ama böyle söylememin sebebi komutun yaşlılığından; for döngüsünden bahsediyorum. Sonra biraz daha geriye, daha yaşlı ve hatta emekli olmuş bir komuta gideceğiz; “goto”. İşte bu komutlar birbirlerinin varisleri, kod yazımını kolaylaştıran, hızlandıran ve hem bize hem de makineye eziyet etmeyen eğitimli torunlar. Dedelerinden aldıkları mirasları günümüzde performansa dönüştüren ufak yardımcılar.
Aşağıda for döngüsü ile yukarıdaki programla aynı mantıkta çalışan bir kod bloğu yazdım, inceleyelim;
1 2 3 4 5 6 7 8 9 |
static void Main(string[] args) { int[] sayilar = { 1, 2, 3, 4, 5 }; for (int i=0; i < sayilar.Length; i++) { Console.Write(sayilar[i]); } Console.ReadKey(); } |
Gördüğünüz üzere fark ortada (2 satır), eski sistem çok yoruyormuş bizi, neymiş o öyle neredeyse parmaklarımız kopacakmış… vs. vs. gibi sözlerle abartmadan önce “for” daki asalete bir bakmanızı isterim. Tabi foreach’de çok asil ama insan “for” a alışınca kolay kolay bırakamıyor. Neyse bu benim tercihim birazda alışkanlık tabi, “goto” yu bırakmakta kolay olmamıştı. Şunu vurgulamak istiyorum çok farkları yok aslında. “for” daki yapıya dikkat etmişsinizdir, illaki dizinin eleman sayısını bilmeniz veya belirtmeniz gerekiyor. İşte bu, for – foreach arasındaki ana fark. Birde kaynak koleksiyonuna foreach ile öğe ekleyip çıkaramıyorsunuz, bunun için for döngüsünü kullanmanız gerekiyor. Bu da diğer bir fark, yeni başlayan arkadaşlar bu son satırı görmemezlikten gelebilirler. foreach sizi ‘dizide neler oluyor’ sorusundan kurtarır. Ve bunu çorba gibi kodlara sorduğunuzda bazı zamanlar çözümün tek çaresi bile olabilir. Lakin “for” yardımcıları ve esnek yapısıyla daha uzun yıllar tahtını paylaşmayacaktır. Yazdığınız kodlarda burada hangisi kullanmalıyım acaba diye hiç endişeniz olmasın, çünkü bu sorunun cevabını binlerce satır yazdıktan sonra sadece parmaklarınız verebilir. O zamana kadar her ikisinide sıra ile kullanmaya özen gösterin. Peki siz yokken biz vardık diyen goto deyimi neler sunuyor bize;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
static void Main(string[] args) { int[] sayilar = { 1, 2, 3, 4, 5 }; int sayac = 0; dongu: if (sayac < sayilar.Length) { Console.Write(sayilar[sayac]); sayac++; goto dongu; } else { Console.ReadKey(); } } |
Bir 5 satır daha fazla kod mu yazdırdı sadece? Değil tabiki… Büyüyen kod sarmallarıyla beraber saç başta yoldurdu zamanında, hayatta kurtardı yeri geldiğinde. Fakat takibi zor bir yapıydı “goto”. Bazen kim nereye gidiyordu, gittiğiniz yer nereye işaret ediyordu diye ararken; “Bir saniye ben ne yapıyordum en son?!” sorusunu sorduruyordu. Ufak programlarda görevini layıkıyla yerine getirdi tabiki, tecrübeler kazandırdı, sistemin eksiklerini gösterdi. Hala kullanılan prosedürel dillerin (C, C++) bir parçasıda olsa kariyerinin doruklarında jübilesini yaptı ve emekliye ayrıldı. Yukarıdaki kod satırını derleyin isterseniz ya da bir benzerini siz yazın. Uygulamalarınızda kullanmasanızda öğrenmenizde fayda var. Nerden geldiğimizi bilirsek – nereye gittiğimizi nereye kadar gidebileceğimizi az çok kestirebiliriz.
foreach() yapısı genel hatları ile böyle, soru ve isteklerinizi yorum alanından çekinmeden paylaşabilirsiniz. Yukarıda kullandığım dil C# fakat genel yapı diğer dillerde de hemen hemen benzer. Arzu ederseniz farklı diller için örnekler ekleyebilir konuyu zenginleştirebilirsiniz. Keyifli kodlar, kolay gelsin.