Bir önce makalemizde LINQ mimarisine giriş yapmıştık. Bugün de Enumerable adlı static sınıf içerisindeki sık kullanılan LINQ metotlarını inceleyeceğiz. Dilerseniz metotları ayrı başlıklar halinde ele alalım. Giriş yapmadan önce birkaç hatırlatma yapmakta fayda var. LINQ metotları, IEnumerable<T> interface’ini implement eden tipler üzerinde çıkmaktadır. Ayrıca, LINQ sorgularından geriye, GetEnumerator metodu olan yani IEnumerable<T> tipini implement bir nesne döner. Bu dönen nesne, bir dizi veya bir koleksiyon gibi içerisinde sorgu sonucunda elde ettiğimiz elemanları taşıyan bir nesne değildir, sorgulanabilir bir nesnedir. Bu sorgulanabilir nesneler üzerinde iterasyon yaparak sonuç kümesini elde ederiz.
Örneklerimize geçmeden önce Urun adında bir sınıf tasarlayalım ve List<Urun> tipinden bir koleksiyon oluşturarak, LINQ metotlarını test edelim.
public class Urun
{
public int Id { get; set; }
public string Ad { get; set; }
public double Fiyat { get; set; }
public Urun(int id, string ad, double fiyat)
{
Id = id;
Ad = ad;
Fiyat = fiyat;
}
public static List<Urun> GetUrunler()
{
List<Urun> urunKoleksiyon = new List<Urun>();
Urun[] urunler = new Urun[]
{
new Urun(1,"Monitör",1200),
new Urun(2,"Klavye",180),
new Urun(3,"Mouse",75),
new Urun(4,"Laptop",2000),
new Urun(5,"Masa",400)
};
urunKoleksiyon.AddRange(urunler);
return urunKoleksiyon;
}
}
- Where Metodu
Adından da anlaşıldığı gibi, filtreleme yapmak için kullanılır. İlk etapta Fiyatı 1000’den büyük olan ürünleri filtreleyelim.
static void Main(string[] args)
{
List<Urun> urunler = Urun.GetUrunler();
IEnumerable<Urun> sorguNesnesi = from urun in urunler
where urun.Fiyat > 1000
select urun;
}
Filtreleme işlemi ile sorgulanabilir bir nesne elde ettik. Bu nesne üzerinde iterasyon yaparak, fiyatı 1000’den büyük olan ürünlerin adını elde etmeye çalışalım. Bundan sonraki örneklerde, bana göre kullanımı daha rahat olan lambda syntax’ını kullanıyor olacağım. Bu sayede, sorgulanabilir kümeler üzerinden tekrar sorgular yapabildiğimizi görmemiz daha rahat olacaktır.
static void Main(string[] args)
{
List<Urun> urunler = Urun.GetUrunler();
IEnumerable<Urun> sorguNesnesi = urunler.Where(urun => urun.Fiyat > 1000);
foreach (Urun u in sorguNesnesi)
Console.WriteLine(u.Ad);
}
foreach’in bulunduğu satıra breakpoint konularak debug işlemi yapıldığında, iterasyonun her adımında, Where içerisindeki koşulun kontrol edildiğini görebiliriz.
Where metodundan geriye sorgulanabilir bir nesne döndüğünü söylemiştik. O halde bu nesne üzerinden yeni sorgular da yazabilir miyiz ? sorguNesnesi adlı değişken üzerinden noktaya basalım ve işte sonuç;
sorguNesnesi geriye IEnumerable<> döndüğü için ve LINQ metotları da IEnumerable<> veya bu tipi implement eden tipler üzerinde çıktığı için sonuca pek de şaşırmamak gerek
Şimdi de Fiyat’ı 1000’den küçük olan ve adı ‘M’ ile başlayan ürünleri elde etmeye çalışalım. Bunu where metodu içerisinde, 2 farklı koşulu and veya or operatörü ile bağlayarak veya 2 kere arka arkaya where metodu kullanarak yapabiliriz. Ancak tek where metodu içerisine yazmak daha performanslıdır.
static void Main(string[] args)
{
List<Urun> urunler = Urun.GetUrunler();
//var sorguNesnesi = urunler.Where(u => u.Fiyat < 1000).Where(u => u.Ad.StartsWith("M"));
var sorguNesnesi = urunler.Where(u => u.Fiyat < 1000 && u.Ad.StartsWith("M"));
foreach (var u in sorguNesnesi)
{
Console.WriteLine(u.Ad);
}
}
Geriye dönen tipi tam olarak bilmesek de , var anahar sözcüğü yardımı ile değişkene alabiliriz. Zaten doğru tipe cast edilecektir.
- Select Metodu
LINQ sorgusunun atıldığı veri kaynağındaki, her bir elemana karşılık, başka bir eleman elde etmek için kullanılır. Dilerseniz bir örnek üzerinden inceleyelim.
Her bir Urun nesnesine karşılık, o Urunun adlarını elde etmek isteyelim.
static void Main(string[] args)
{
List<Urun> urunler = Urun.GetUrunler();
IEnumerable<string> sorguNesnesi = urunler.Select(u => u.Ad);
foreach (string urunAdi in sorguNesnesi)
{
Console.WriteLine(urunAdi);
}
}
Dikkat ederseniz sorgudan geriye IEnumerable<string> döndü. Çünkü her bir ürüne karşılık o ürünün adını almak istedik, yani string tiplerinden oluşan ve sorgulanabilir bir nesne elde etmiş olduk.
T-SQL ifadelerinde select ile birden fazla kolon elde edebiliriz. Aynı işlemi select metodu ile de gerçekleştirmemiz mümkündür. Bunun için her bir nesneye karşılık anonim bir tip oluştururuz. urunler içerisindeki her bir Urun için adını ve fiyatlarının %18 kdv eklenmiş halini elde etmeye çalışalım.
class Program
{
static void Main(string[] args)
{
List<Urun> urunler = Urun.GetUrunler();
var sorguNesnesi = urunler.Select(u => new { Ad = u.Ad, Fiyat = u.Fiyat * 1.18 });
//Kolon adı property adı ile aynı olacaksa, yazmak zorunda değiliz. u.Ad , Fiyat = u.Fiyat * 1.18 şeklinde de yazabiliriz.
foreach (var result in sorguNesnesi)
Console.WriteLine("{0} adlı ürünün fiyatı {1} TL'ye yükseldi", result.Ad, result.Fiyat);
}
}
Ekran çıktımız aşağıdaki gibi olacaktır.
- OrderBy ve OrderByDescending Metotları
Adından da anlaşılacağı üzere, sıralama yapmak için kullanılırlar. ürünleri fiyatlarına göre artan ve azalan şekilde sıralayalım.
static void Main(string[] args)
{
List<Urun> urunler = Urun.GetUrunler();
IOrderedEnumerable<Urun> sorguNesnesi = urunler.OrderBy(u => u.Fiyat);
foreach (Urun urun in sorguNesnesi)
Console.WriteLine("{0} - {1}", urun.Ad, urun.Fiyat);
Console.WriteLine("********************************************************");
//sorgu nesnesini bir değişkene almadadan direkt olarak itersyon yapabiliriz.
foreach (Urun urun in urunler.OrderByDescending(u => u.Fiyat))
Console.WriteLine("{0} - {1}", urun.Ad, urun.Fiyat);
}
}
OrderBy ve OrderByDescending metotları geriye IOrderedEnumerable<T> döndürürler. Go to definition dediğimiz takdirde bu interface’in IEnumerable<T>’yi implement ettiğini görürüz.
- Take Metodu
T-SQL deki TOP ifadesine karşılık gelir ve geriye sorgulanabilir bir nesne döner.
Fiyatlarına göre artan olarak sıraladığımız ürünlerin ilk 3’ünü alalım.
static void Main(string[] args)
{
List<Urun> urunler = Urun.GetUrunler();
foreach (Urun urun in urunler.OrderBy(u => u.Fiyat).Take(3))
{
Console.WriteLine("{0} - {1}",urun.Ad,urun.Fiyat);
}
}
- Sum Metodu
Adı ‘M’ ile başlayan ürünlerin fiyatlarını toplayarak ekrana yazdıralım.
static void Main(string[] args)
{
List<Urun> urunler = Urun.GetUrunler();
double toplamFiyat = urunler.Where(u => u.Ad.StartsWith("M")).Sum(u => u.Fiyat);
Console.WriteLine("Toplam Fiyat = {0}", toplamFiyat);
}
- Max ve Min Metotları
urunler içerisindeki en büyük ve en küçük fiyat değerlerini elde edelim ve ekrana yazdıralım.
static void Main(string[] args)
{
List<Urun> urunler = Urun.GetUrunler();
double enYuksekFiyat = urunler.Max(urun => urun.Fiyat);
double enDusukFiyat = urunler.Min(urun => urun.Fiyat);
Console.WriteLine("En Yüksek : {0} - En Düşük : {1}", enYuksekFiyat, enDusukFiyat);
}
Max ve Min fonksiyonlarının parametresiz versiyonu da mevcuttur ancak karşılaştırmayı IComparable interface’ine göre yapar.Dolayısı ile bu versiyonu kullanabilmemiz için veri kaynağının içerisinde bulunan tipin IComparable interface’ini implement etmesi gerekmektedir. Bu örnek için, karşılaştırmayı fiyatlara göre yapalım.
public class Urun : IComparable
{
public int Id { get; set; }
public string Ad { get; set; }
public double Fiyat { get; set; }
public Urun(int id, string ad, double fiyat)
{
Id = id;
Ad = ad;
Fiyat = fiyat;
}
public static List<Urun> GetUrunler()
{
List<Urun> urunKoleksiyon = new List<Urun>();
Urun[] urunler = new Urun[]
{
new Urun(1,"Monitör",1200),
new Urun(2,"Klavye",180),
new Urun(3,"Mouse",75),
new Urun(4,"Laptop",2000),
new Urun(5,"Masa",400)
};
urunKoleksiyon.AddRange(urunler);
return urunKoleksiyon;
}
public int CompareTo(object obj)
{
Urun gelen = (Urun)obj;
if (this.Fiyat > gelen.Fiyat)
return 1;
else if (this.Fiyat < gelen.Fiyat)
return -1;
else
return 0;
}
}
Parametresiz versiyonlarda geriye Urun dönecektir.
static void Main(string[] args)
{
List<Urun> urunler = Urun.GetUrunler();
double enYuksekFiyat = urunler.Max().Fiyat;
double enDusukFiyat = urunler.Min().Fiyat;
Console.WriteLine("En Yüksek : {0} - En Düşük : {1}", enYuksekFiyat, enDusukFiyat);
}
Max ve Min metotları, hangi koşullara göre çalışacaklarını IComparable sayesinde bilmektedirler. Alacağımız sonuç ilk yaptığımız örnek ile aynı olacaktır.
- Count Metodu
Linq kaynağı içerisinde bulunan nesnelerin sayısını döndürür. Adı ‘M’ ile başlayan ürünlerin sayısını ekrana yazdıralım. Bu koşulu Where metodu içerisine yazıp ardından Count metodunu çağırabildiğimiz gibi, direkt olarak Count içerisine de de yazabilmemiz mümkündür.
static void Main(string[] args)
{
List<Urun> urunler = Urun.GetUrunler();
//int urunSayisi = urunler.Where(u => u.Ad.StartsWith("M")).Count();
int urunSayisi = urunler.Count(u => u.Ad.StartsWith("M"));
Console.WriteLine("Adı 'M' ile başlayan {0} adet ürün mevcut", urunSayisi);
}
- ToList ve ToArray Metotları
Select, Where, Take, OrderBy gibi metotlar sonucunda geriye sorgulanabilir bir nesnenin döndüğünü görmüştük. ToList ve ToArray metotları ile, sorgu sonuçlarının bir kopyasını alarak belleğe çıkarabilir ve bunu bir liste koleksiyonuna ya da bir dizi içerisine atabiliriz.
static void Main(string[] args)
{
List<Urun> urunler = Urun.GetUrunler();
//Fiyatı 1000'den büyük olan ürünleri, fiyatlarına göre artan şekilde sıralayarak bir List koleksiyonuna alalım.
List<Urun> sonucKumesi = urunler.Where(u => u.Fiyat > 1000).OrderBy(u => u.Fiyat).ToList();
Console.WriteLine("{0} elemanlı sonuç kümesinin ilk elemanının adı : {1}", sonucKumesi.Count(), sonucKumesi[0].Ad);
//adında 'a' karakteri olan ürünlerin Id'lerini bir dizi içerisinde toplayalım
int[] sonucKumesi2 = urunler.Where(u => u.Ad.Contains('a')).Select(u => u.Id).ToArray();
Console.WriteLine("{0} elemanlı sonuç kümesinin ikinci elemanının id'si : {1}", sonucKumesi2.Count(), sonucKumesi2[1]);
}
-First ve FirstOrDefault Metotları
LINQ Sorgularından elde edilen sorgu nesnesini çalıştırarak, filtreden geçen ilk elemanı elde etmemizi sağlarlar. First metotu, eğer sorgu nesnesinden sonuç gelmesse hata verir, ancak FirstOrDefault metodu, o tipin default değerini döndürür.
static void Main(string[] args)
{
List<Urun> urunler = Urun.GetUrunler();
Urun urun = urunler.Where(u => u.Fiyat > 5000).FirstOrDefault();
if (urun != null)
Console.WriteLine(urun.Ad);
else
Console.WriteLine("Sorgu sonucunda nesne elde edilmedi");
//Metodun 2. parametresinde, where metodu içerisine yazdığımız filtreleme koşulunu direkt olarak yazabiliriz.
Urun urun2 = urunler.FirstOrDefault(u => u.Fiyat < 1000);
Console.WriteLine(urun2.Ad);
}
Fiyatı 5000’den büyük olan ilk ürünü almak istediğimiz kısımda, First metodunu kullansaydık exception alacaktık.
- Single ve SingleOrDefault Metotları
First ve FirstOrDefault metotları, LINQ kaynağındaki ilk sonucu elde etmemizi sağlar. Single metodu ise, eğer verdiğimiz koşulu sağlayan başka bir eleman varsa, yani koşuldan geçen eleman sayısı birden fazla ise hata almamızı sağlar. SingleOrDefault metodu da, geriye bir eleman dönmez ise o tipin default değerini elde etmemizi sağlar.
static void Main(string[] args)
{
List<Urun> urunler = Urun.GetUrunler();
//kaynakta fiyatı 5000'den büyük ürün olmadığı için hata alırız.
Urun urun = urunler.Where(u => u.Fiyat > 5000).Single();
//kaynakta fiyatı 5000'den büyük ürün olmadığı için urun2 null'dır
Urun urun2 = urunler.Where(u => u.Fiyat > 5000).SingleOrDefault();
//kaynakta fiyatı 1000'den büyük olan 2 adet ürün mevcuttur. Exception alırız.
Urun urun3 = urunler.Where(u => u.Fiyat > 1000).SingleOrDefault();
//kaynakta fiyatı 1500'den büyük olan tek ürün vardır. Geriye o ürünü döner. Ekran çıktısı "Laptop" şeklinde olacaktır.
Urun urun4 = urunler.Where(u => u.Fiyat > 1500).SingleOrDefault();
}
- All ve Any Metotları
All metodu, verdiğimiz koşul kaynaktaki tüm elemanlar tarafından sağlanıyorsa true döner, bir tanesi bile koşulu bozuyorsa false döner. Any metodu ise, koşulu sağlayan herhangi bir eleman varsa true döner, hiçbiri sağlamıyor ise false döner.
static void Main(string[] args)
{
List<Urun> urunler = Urun.GetUrunler();
//kaynaktaki tüm ürünlerin fiyatı 5000'den küçük olduğu için true döner.
bool durum = urunler.All(u => u.Fiyat < 5000);
//kaynaktaki tüm ürünlerin fiyatı 1000'den büyük olmadığı için false döner. Koşulu bozan tek bir eleman bile olsa false döner.
bool durum2 = urunler.All(u => u.Fiyat > 1000);
//kaynakta adı "M" ile başlayan en az bir eleman varsa true döner. Bizim kaynağımızda adı "M" ile başlayan 3 adet ürün mevcut olduğundan dolayı durum3'de true değeri vardır.
bool durum3 = urunler.Any(u => u.Ad.StartsWith("M"));
//kaynataki hiçbir elemanın Id'si 0'dan küçük değildir. False döner.
bool durum4 = urunler.Any(u => u.Id < 0);
}
- TakeWhile Metodu
Verilen koşul sağlandığı sürece okuma yapar. While döngüsü gibi düşünebiliriz.
static void Main(string[] args)
{
List<Urun> urunler = Urun.GetUrunler();
//fiyat 1000'den küçük olduğu sürece okuma yap diyoruz. Ancak ilk ürün olan monitörün fiyatı 1200 lira olduğundan okuma işlemi sonlanır.
IEnumerable<Urun> sorguNesnesi = urunler.TakeWhile(u => u.Fiyat < 1000);
if (sorguNesnesi.Count() == 0)
{
Console.WriteLine("hiç eleman okunamadı");
}
//Fiyata göre azalan şekilde sıraladığımız kaynak üzerindeki ilk elemanın fiyatı 1000'den büyük olduğu için okuma devam eder. 3.eleman Masa'nın fiyatı 1000'den küçük olduğu için okuma sonlanır.
foreach (Urun urn in urunler.OrderByDescending(u => u.Fiyat).TakeWhile(u => u.Fiyat > 1000))
{
Console.WriteLine(urn.Ad);
}
}
- ElementAt ve ElementAtOrDefault Metotları
Parametre olarak verilen index'e sahip elemanı geriye döndürür. ElementAt metodu, verilen index’e sahip bir eleman mevcut değilse hata verir, ElementAtOrDefault metodu ise o tipin default değerini döner.
static void Main(string[] args)
{
List<Urun> urunler = Urun.GetUrunler();
//Exception alırız. Kaynaktaki son elemanın index'i 4'dür.
Urun urn = urunler.OrderBy(u => u.Fiyat).ElementAt(5);
Console.WriteLine(urn.Ad);
Urun urn2 = urunler.OrderByDescending(u => u.Fiyat).ElementAtOrDefault(0);
Console.WriteLine(urn2.Ad); // Ekran çıktısı "Laptop" olacaktır.
}
8 yorum:
Çok teşekkürler emeğinize sağlık
emeğiniz için teşekkürler. Gayet faydalı bir makale olmuş
güzel çalışma. elinize sağlık
Aklına fikrine eline sağlık.
bravooooooooooooooo
Eyvallah hocam çok yardımcı oldun
Çok güzel emeğinize sağlık.
Çok faydalı bir çalışma.. Teşekkürler..
Yorum Gönder