20.06.16 21:15
LINQ - Temel İşlemler - Gruplama (Grouping)
Gruplama, sorguların güçlü özelliklerinden biridir. Gruplama ile bildirilen listedeki aynı veriyi içeren elemanlar bir grup listesi (alt liste) oluşturur. Örneğin müşteriler listemizdeki elemanlar bulundukları şehire göre gruplandırılabilir. Sonuçta herbir şehirdeki müşterilerden oluşan ayrı ayrı listelerimiz olur. Bu şekilde hem grupların eleman sayısı vb. bilgilerine, hem de her bir grubu ayrı ayrı gezerek grubu oluşturan elemanların bilgilerine erişebilir, gruplara göre işlemler gerçekleştirebiliriz. Gruplanan elemanlar IGrouping<TKey, TElement> arayüzünü uygulayan bir koleksiyon olarak dönerler. Buradaki T harfi herhangi bir tip anlamındadır. TKey 'in tipi gruplama için kullanılan ortak özelliğin tipine karşılık gelir. Bu arayüz kendisi de IEnumerable<T> arayüzünü uyguladığı için ( T , TElement olmak üzere), elemanları tek tek gezilebilir. TElement ise grup elemanlarının tipini temsil eder. Şu örneği inceleyin. using System; using System.Collections.Generic; using System.Linq; namespace LinQLinQ { class Program { public class Ogrenci { public string Adi { get; set; } public string Soyadi { get; set; } public int No { get; set; } public List<int> Yazililar; } public static List<Ogrenci> OgrencileriGetir() { List<Ogrenci> Ogrenciler = new List<Ogrenci> { new Ogrenci {Adi="Kenan", Soyadi="Oran", No=111, Yazililar = new List<int> {97, 72, 60}}, new Ogrenci {Adi="Erhan", Soyadi="Erkanlı", No=112, Yazililar = new List<int> {75, 84, 39}}, new Ogrenci {Adi="Tekin", Soyadi="Uğurlu", No=113, Yazililar = new List<int> {99, 89, 95}}, new Ogrenci {Adi="Mehmet", Soyadi="Emre", No=114, Yazililar = new List<int> {72, 81, 84}}, new Ogrenci {Adi="Ercan", Soyadi="Orak", No=115, Yazililar = new List<int> {97, 89, 82}}, }; return Ogrenciler; } static void Main(string[] args) { List<Ogrenci> Ogrenciler = OgrencileriGetir(); var ogrenciGruplari = from ogr in Ogrenciler group ogr by ogr.Soyadi[0]; // LINQ Yöntem Sözdizimi ile sorgu : /* var ogrenciGruplari = Ogrenciler.GroupBy(ogr => ogr.Soyadi[0]); */ foreach (var ogrenciGrubu in ogrenciGruplari) { Console.WriteLine(ogrenciGrubu.Key); foreach (var ogr in ogrenciGrubu) { Console.WriteLine(" {0}, {1}", ogr.Soyadi, ogr.Adi); } } } } } Çıktı: O Oran, Kenan Orak, Ercan E Erkanlı, Erhan Emre, Mehmet U Uğurlu, Tekin Örnekteki sorgu, öğrencileri soyadlarının ilk harflerine göre gruplandırır ve herbiri IGrouping<TKey, TElement> arayüzünü uygulayan IGrouping<char, Ogrenci> tipinde bir grup listesini IEnumerable<T> biçiminde döndürür. Yani dönen değerin tam tipi IEnumerable<IGrouping<char, Ogrenci>> olacaktır. Her bir grupta soyadı aynı harfle başlayan (A ile, B ile ... Z ile başlayanlar gibi) öğrencilerin listesi bulunacaktır. IGrouping<char, Ogrenci> tipindeki char , grubun anahtarıdır. Bizim örneğimizde anahtar olarak ogr.Soyadi[0] , yani öğrencinin soyadının 0. harfi (ilk harfi) seçildiğinden tip char (bilindiği gibi string[x] şeklinde bir istek string'in x. karakterini char olarak verir) olmuştur ve her bir grupta ( IGrouping<TKey, TElement> listesinde) gruptakilerin soyadlarının başladığı harfe karşılık gelir. Liste Ogrenci isimli bir sınıfın örneklerini tuttuğundan 2. tip ( TElement ) Ogrenci olmuştur. Dıştaki foreach döngüsü, ogrenciGruplari sorgusunun elemanlarını gezecek ve her bir elemanı ogrenciGrubu ismiyle temsil edecektir. Dolayısıyla sorgunun türü IEnumerable<IGrouping<char, Ogrenci>> olduğundan her bir eleman IGrouping<char, Ogrenci> tipinde bir liste olacaktır. İçteki döngüden önce grubun anahtarı (örneğimizde gruptaki öğrencilerin hepsinin soyadlarının baş harfi) çıktıya yazdırılıyor. İçteki döngüde, dıştaki döngünün her dönüşünde seçilen ogrenciGrubu isimli IGrouping<char, Ogrenci> tipindeki listenin elemanları geziliyor. Bu listenin elemanları Ogrenci tipinde olduğundan döngüdeki seri değişkeni olan ogr her seferinde bir öğrenciye karşılık gelmekte ve döngü içinde de ogr'nin temsil ettiği Ogrenci tipindeki nesnenin Soyadi ve Adi alanlarının değerleri yazdırılmaktadır. Bu örnekteki sorguyu devam ettirmek isterseniz group cümleciğine into ile daha sonraki işlemlerde kullanılmak üzere bir tanımlayıcı değişken eklemeniz gerekir. Üstteki örneğin where ve orderby kullanılmış şekli şöyle olur. using System; using System.Collections.Generic; using System.Linq; namespace LinQLinQ { class Program { public class Ogrenci { public string Adi { get; set; } public string Soyadi { get; set; } public int No { get; set; } public List<int> Yazililar; } public static List<Ogrenci> OgrencileriGetir() { List<Ogrenci> Ogrenciler = new List<Ogrenci> { new Ogrenci {Adi="Kenan", Soyadi="Oran", No=111, Yazililar = new List<int> {97, 72, 60}}, new Ogrenci {Adi="Erhan", Soyadi="Erkanlı", No=112, Yazililar = new List<int> {75, 84, 39}}, new Ogrenci {Adi="Tekin", Soyadi="Uğurlu", No=113, Yazililar = new List<int> {99, 89, 95}}, new Ogrenci {Adi="Mehmet", Soyadi="Emre", No=114, Yazililar = new List<int> {72, 81, 84}}, new Ogrenci {Adi="Ercan", Soyadi="Orak", No=115, Yazililar = new List<int> {97, 89, 82}}, }; return Ogrenciler; } static void Main(string[] args) { List<Ogrenci> Ogrenciler = OgrencileriGetir(); var ogrenciGruplari = from ogr in Ogrenciler group ogr by ogr.Soyadi[0] into basHarfGrubu where basHarfGrubu.Count() > 1 orderby basHarfGrubu.Key select basHarfGrubu; // LINQ Yöntem Sözdizimi ile sorgu : /* var ogrenciGruplari = Ogrenciler.GroupBy(ogr => ogr.Soyadi[0]) .Where(basHarfGrubu => basHarfGrubu.Count() > 1) .OrderBy(basHarfGrubu => basHarfGrubu.Key); */ foreach (var ogrenciGrubu in ogrenciGruplari) { Console.WriteLine(ogrenciGrubu.Key); foreach (var ogr in ogrenciGrubu) { Console.WriteLine("{0}, {1}", ogr.Soyadi, ogr.Adi); } } Console.ReadKey(); } } } Çıktı: Çıktı : E Erkanlı, Erhan Emre, Mehmet O Oran, Kenan Orak, Ercan Üstte bahsedilen tanımlayıcı değişken örnekte "into" ifadesinin yanındaki "basHarfGrubu" ifadesidir. Örnekte görüldüğü gibi sorgunun 2. satırında grubun "basHarfGrubu" isimli bir değişkene atanması ve eleman sayısı 1'den büyük olan grupların seçilmesi, grupların grup anahtarına (IGrouping<TKey, TElement> biçiminin Key özelliği) göre (örneğimizde soyadların baş harfleri yani harfe göre) sıralanması bildirilmiş. Diğer LINQ Makaleleri: LINQ Örnekleri makalelerinde kullanılan verikaynağı LINQ (Language Integrated Query - Dile Entegre Edilmiş Sorgu) Nedir? LINQ Sağlayıcıları (LINQ Providers) LINQ Yöntem Sözdizimi (LINQ Method Syntax) LINQ - Temel İşlemler - Bir Veri Kaynağı Bildirme ve Seçme (From ve Select) LINQ - Temel İşlemler - Süzme (Filtering) LINQ - Temel İşlemler - Sıralama (Ordering) LINQ - Temel İşlemler - Gruplama (Grouping) (Bu makale) LINQ - Temel İşlemler - Birleştirme (Joining) LINQ - Deferred Execution - Ertelenmiş Çalıştırma LINQ - Immediate Execution - Anında Çalıştırma LINQ - Query Reuse - Sorgunun Yeniden Kullanımı LINQ - Kısıtlama (Restriction) Kullanım Örnekleri LINQ - Yansıtma (Projection) - Select Kullanım Örnekleri LINQ - Yansıtma (Projection) - SelectMany Kullanım Örnekleri LINQ - Bölümleme (Partitioning) Örnekleri LINQ - Sıralama (Ordering) Örnekleri LINQ - Gruplama (Grouping) Örnekleri LINQ - Küme (Set) Örnekleri LINQ - Dönüşüm (Conversion) Örnekleri LINQ - Eleman (Element) Seçimi Örnekleri LINQ - Oluşturma (Generation) Örnekleri LINQ - Miktar Belirleyiciler (Quantifiers) Örnekleri LINQ - Yığın (Aggregate) Örnekleri LINQ - Birleştirme (Join) İşlemleri LINQ - Özel Dizilim (Custom Sequence) Örneği LINQ - Concat ve SequenceEqual İle Örnekle r
Ekleyen: canora
Değiştiren: canora
09.04.16 20:43
LINQ - Temel İşlemler - Gruplama (Grouping)
Gruplama, sorguların güçlü özelliklerinden biridir. Gruplama ile bildirilen listedeki aynı veriyi içeren elemanlar bir grup listesi (alt liste) oluşturur. Örneğin müşteriler listemizdeki elemanlar bulundukları şehire göre gruplandırılabilir. Sonuçta herbir şehirdeki müşterilerden oluşan ayrı ayrı listelerimiz olur. Bu şekilde hem grupların eleman sayısı vb. bilgilerine, hem de her bir grubu ayrı ayrı gezerek grubu oluşturan elemanların bilgilerine erişebilir, gruplara göre işlemler gerçekleştirebiliriz. Gruplanan elemanlar IGrouping<TKey, TElement> arayüzünü uygulayan bir koleksiyon olarak dönerler. Buradaki T harfi herhangi bir tip anlamındadır. TKey 'in tipi gruplama için kullanılan ortak özelliğin tipine karşılık gelir. Bu arayüz kendisi de IEnumerable<T> arayüzünü uyguladığı için ( T , TElement olmak üzere), elemanları tek tek gezilebilir. TElement ise grup elemanlarının tipini temsil eder. Şu örneği inceleyin. using System; using System.Collections.Generic; using System.Linq; namespace LinQLinQ { class Program { public class Ogrenci { public string Adi { get; set; } public string Soyadi { get; set; } public int No { get; set; } public List<int> Yazililar; } public static List<Ogrenci> OgrencileriGetir() { List<Ogrenci> Ogrenciler = new List<Ogrenci> { new Ogrenci {Adi="Kenan", Soyadi="Oran", No=111, Yazililar = new List<int> {97, 72, 60}}, new Ogrenci {Adi="Erhan", Soyadi="Erkanlı", No=112, Yazililar = new List<int> {75, 84, 39}}, new Ogrenci {Adi="Tekin", Soyadi="Uğurlu", No=113, Yazililar = new List<int> {99, 89, 95}}, new Ogrenci {Adi="Mehmet", Soyadi="Emre", No=114, Yazililar = new List<int> {72, 81, 84}}, new Ogrenci {Adi="Ercan", Soyadi="Orak", No=115, Yazililar = new List<int> {97, 89, 82}}, }; return Ogrenciler; } static void Main(string[] args) { List<Ogrenci> Ogrenciler = OgrencileriGetir(); var ogrenciGruplari = from ogr in Ogrenciler group ogr by ogr.Soyadi[0]; // LINQ Yöntem Sözdizimi ile sorgu : /* var ogrenciGruplari = Ogrenciler.GroupBy(ogr => ogr.Soyadi[0]); */ foreach (var ogrenciGrubu in ogrenciGruplari) { Console.WriteLine(ogrenciGrubu.Key); foreach (var ogr in ogrenciGrubu) { Console.WriteLine(" {0}, {1}", ogr.Soyadi, ogr.Adi); } } } } } Çıktı: O Oran, Kenan Orak, Ercan E Erkanlı, Erhan Emre, Mehmet U Uğurlu, Tekin Örnekteki sorgu, öğrencileri soyadlarının ilk harflerine göre gruplandırır ve herbiri IGrouping<TKey, TElement> arayüzünü uygulayan IGrouping<char, Ogrenci> tipinde bir grup listesini IEnumerable<T> biçiminde döndürür. Yani dönen değerin tam tipi IEnumerable<IGrouping<char, Ogrenci>> olacaktır. Her bir grupta soyadı aynı harfle başlayan (A ile, B ile ... Z ile başlayanlar gibi) öğrencilerin listesi bulunacaktır. IGrouping<char, Ogrenci> tipindeki char , grubun anahtarıdır. Bizim örneğimizde anahtar olarak ogr.Soyadi[0] , yani öğrencinin soyadının 0. harfi (ilk harfi) seçildiğinden tip char (bilindiği gibi string[x] şeklinde bir istek string'in x. karakterini char olarak verir) olmuştur ve her bir grupta ( IGrouping<TKey, TElement> listesinde) gruptakilerin soyadlarının başladığı harfe karşılık gelir. Liste Ogrenci isimli bir sınıfın örneklerini tuttuğundan 2. tip ( TElement ) Ogrenci olmuştur. Dıştaki foreach döngüsü, ogrenciGruplari sorgusunun elemanlarını gezecek ve her bir elemanı ogrenciGrubu ismiyle temsil edecektir. Dolayısıyla sorgunun türü IEnumerable<IGrouping<char, Ogrenci>> olduğundan her bir eleman IGrouping<char, Ogrenci> tipinde bir liste olacaktır. İçteki döngüden önce grubun anahtarı (örneğimizde gruptaki öğrencilerin hepsinin soyadlarının baş harfi) çıktıya yazdırılıyor. İçteki döngüde, dıştaki döngünün her dönüşünde seçilen ogrenciGrubu isimli IGrouping<char, Ogrenci> tipindeki listenin elemanları geziliyor. Bu listenin elemanları Ogrenci tipinde olduğundan döngüdeki seri değişkeni olan ogr her seferinde bir öğrenciye karşılık gelmekte ve döngü içinde de ogr'nin temsil ettiği Ogrenci tipindeki nesnenin Soyadi ve Adi alanlarının değerleri yazdırılmaktadır. Bu örnekteki sorguyu devam ettirmek isterseniz group cümleciğine into ile daha sonraki işlemlerde kullanılmak üzere bir tanımlayıcı değişken eklemeniz gerekir. Üstteki örneğin where ve orderby kullanılmış şekli şöyle olur. using System; using System.Collections.Generic; using System.Linq; namespace LinQLinQ { class Program { public class Ogrenci { public string Adi { get; set; } public string Soyadi { get; set; } public int No { get; set; } public List<int> Yazililar; } public static List<Ogrenci> OgrencileriGetir() { List<Ogrenci> Ogrenciler = new List<Ogrenci> { new Ogrenci {Adi="Kenan", Soyadi="Oran", No=111, Yazililar = new List<int> {97, 72, 60}}, new Ogrenci {Adi="Erhan", Soyadi="Erkanlı", No=112, Yazililar = new List<int> {75, 84, 39}}, new Ogrenci {Adi="Tekin", Soyadi="Uğurlu", No=113, Yazililar = new List<int> {99, 89, 95}}, new Ogrenci {Adi="Mehmet", Soyadi="Emre", No=114, Yazililar = new List<int> {72, 81, 84}}, new Ogrenci {Adi="Ercan", Soyadi="Orak", No=115, Yazililar = new List<int> {97, 89, 82}}, }; return Ogrenciler; } static void Main(string[] args) { List<Ogrenci> Ogrenciler = OgrencileriGetir(); var ogrenciGruplari = from ogr in Ogrenciler group ogr by ogr.Soyadi[0] into basHarfGrubu where basHarfGrubu.Count() > 1 orderby basHarfGrubu.Key select basHarfGrubu; // LINQ Yöntem Sözdizimi ile sorgu : /* var ogrenciGruplari = Ogrenciler.GroupBy(ogr => ogr.Soyadi[0]) .Where(basHarfGrubu => basHarfGrubu.Count() > 1) .OrderBy(basHarfGrubu => basHarfGrubu.Key); */ foreach (var ogrenciGrubu in ogrenciGruplari) { Console.WriteLine(ogrenciGrubu.Key); foreach (var ogr in ogrenciGrubu) { Console.WriteLine("{0}, {1}", ogr.Soyadi, ogr.Adi); } } Console.ReadKey(); } } } Çıktı: Çıktı : E Erkanlı, Erhan Emre, Mehmet O Oran, Kenan Orak, Ercan Üstte bahsedilen tanımlayıcı değişken örnekte "into" ifadesinin yanındaki "basHarfGrubu" ifadesidir. Örnekte görüldüğü gibi sorgunun 2. satırında grubun "basHarfGrubu" isimli bir değişkene atanması ve eleman sayısı 1'den büyük olan grupların seçilmesi, grupların grup anahtarına (IGrouping<TKey, TElement> biçiminin Key özelliği) göre (örneğimizde soyadların baş harfleri yani harfe göre) sıralanması bildirilmiş.
Ekleyen: canora