Halad Programozs Lambda kifejezsek LINQ V 1 0
Haladó Programozás Lambda kifejezések LINQ V 1. 0 Szabó Zsolt, Óbudai Egyetem, 2011 szabo. zsolt@nik. uni-obuda. hu 1
Haladó Programozás Lambda kifejezések LINQ V 1. 0 Szabó Zsolt, Óbudai Egyetem, 2011 szabo. zsolt@nik. uni-obuda. hu 2
Lambda kifejezések • Cél: az írt kód lényeges lerövidítése (+ closures: működés egységbe zárása) • Veszély: nagyon könnyen hozhatunk létre nehezen olvasható kódot Eddigi használat: • 1) delegate deklarálása: típusok fixálása (be- és kimenet) delegate int del(int i); • 2) anonymous metódus írása del negyzet = delegate (int x) { return x * x; }; • 3) Eljárás meghívása int j = negyzet(5); //j = 25 V 1. 0 Szabó Zsolt, Óbudai Egyetem, 2011 szabo. zsolt@nik. uni-obuda. hu 3
Lambda kifejezések • Új operátor: => (Lambda operátor) , a bemenet és a kimenet összekötésére használt • Szintaxis: (paraméter[ek]) => kimenetet meghatározó kifejezés Lambda kifejezés használata: • 1) delegate deklarálása: típusok fixálása delegate int del(int i); • 2) delegate-hez változó hozzárendelése és lambda operátor del negyzet = (x) => x * x; • 3) Eljárás meghívása int j = negyzet(5); //j = 25 V 1. 0 Szabó Zsolt, Óbudai Egyetem, 2011 szabo. zsolt@nik. uni-obuda. hu 4
Lambda kifejezések • delegate int del(int i, int j); del my. Delegate = (x, y) => x + y; int j = my. Delegate(5, 10); //j = 15 • Delegate nélkül is használható: Func<int, int> my. Func = (x) => x * x; int j = my. Func(5); //j = 25 • Func<int, int > my. Func 2 = (x, y) => x + y; int j = my. Func 2(5, 10); //j = 15 • A paraméterek típusozása nem kötelező, csak speciális esetekben V 1. 0 Szabó Zsolt, Óbudai Egyetem, 2011 szabo. zsolt@nik. uni-obuda. hu 5
Lambda kifejezések • Rekurzió: problémás: a változó definiálásához önmagát használom, de az adott változónak még nincs értéke • Func<int, int> Fakt = (x) => x == 1 ? 1 : x * Fakt(x - 1); // Use of unassigned variable • Csúnya fix: Func<int, int> Fakt = null; Fakt = (x) => x == 1 ? 1 : x * Fakt(x - 1); V 1. 0 Szabó Zsolt, Óbudai Egyetem, 2011 szabo. zsolt@nik. uni-obuda. hu 6
Lambda kifejezések • A helyes rekurzióhoz rekurzív megvalósítású lambda delegate kell – a Funct nem ilyen. • Rekurzív delegate: delegate int Recursive (Recursive r, int n); • Funct<BE, KI> -hoz hasonló rekurzív + generikus delegate: delegate KI Recursive <BE, KI>( Recursive <BE, KI> r, BE a); • Recursive <int, int> Fakt 2 = (f, x) => x == 1 ? 1 : x * f(f, x-1); j = Fakt 2(Fakt 2, 5); //j = 120 V 1. 0 Szabó Zsolt, Óbudai Egyetem, 2011 szabo. zsolt@nik. uni-obuda. hu 7
Lambda kifejezések • A lambda kifejezések tényleges ereje a LINQ módszerekkel együttesen használva derül ki, ahol a paraméter részbe kerülhetnek lambda kifejezések • int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; numbers. Where( n => n > 5); Az ötnél nagyobbak listája numbers. Count(n => n % 2 == 1); A páratlanok darabszáma • Nézzük, hogy ez hogyan is történik… V 1. 0 Szabó Zsolt, Óbudai Egyetem, 2011 szabo. zsolt@nik. uni-obuda. hu 8
Haladó Programozás Lambda kifejezések LINQ V 1. 0 Szabó Zsolt, Óbudai Egyetem, 2011 szabo. zsolt@nik. uni-obuda. hu 9
LINQ = Language Integrated Queries • Gyűjtemények szintaktikailag egyszerű és forrásfüggetlen kezelése • Szintaktikailag egyszerű: ciklusok és elágazások halmaza helyett lekérdező operátorokat használunk • Forrásfüggetlen (MVC elv): teljesen mindegy, hogy a gyűjtemény adatforrása tömb, lista, XML, adatbázis – az eljárások ugyanazok Megjelenítés réteg (VEP) V 1. 0 Üzleti logika réteg (OOP, PPT) Szabó Zsolt, Óbudai Egyetem, 2011 szabo. zsolt@nik. uni-obuda. hu Adat (erőforrás) réteg (ADB) 10
LINQ to … ? • LINQ To Objects: Memóriában lévő gyűjtemények, listák, tömbök feldolgozását teszi lehetővé (lényegében minden olyan osztállyal működik amely megvalósítja az IEnumerable<T> interfészt ). • LINQ To XML: XML dokumentumok lekérdezését és szerkesztését teszi lehetővé. • LINQ To SQL (DLINQ) és LINQ To Entities (Entity Framework, VS 2008 SP 1): relációs adatbázisokon végezhetünk műveleteket (MS SQL-Server, de vannak kiterjesztések más szerverekhez is) • Az első két típust a HP óra keretében tárgyaljuk • Most: LINQ To Objects: listák, tömbök kezelése V 1. 0 Szabó Zsolt, Óbudai Egyetem, 2011 szabo. zsolt@nik. uni-obuda. hu 11
LINQ Gyűjtemények class diak { public string nev; public int kreditek; public diak( string ujnev, int ujkreditek) { nev = ujnev; kreditek = ujkreditek; } public override string To. String() { return nev + " - " + kreditek; } } V 1. 0 Szabó Zsolt, Óbudai Egyetem, 2011 szabo. zsolt@nik. uni-obuda. hu 12
LINQ Gyűjtemények int[] elso = new int[] { 2, 4, 6, 8, 2, 1, 2, 3 }; int[] masodik = new int[] { 1, 3, 5, 7, 1, 1, 2, 3 }; string [] strtomb = new string [] { "Béla" , "Jolán" , "Bill" , "Shakespeare" , "Verne" , "Jókai" }; List<diak> diakok = new List<diak>(); diakok. Add( new diak("Első Egon" , 52)); diakok. Add( new diak("Második Miksa" , 97)); diakok. Add( new diak("Harmadik Huba" , 10)); diakok. Add( new diak("Negyedik Néró" , 89)); diakok. Add( new diak("Ötödik Ödön" , 69)); V 1. 0 Szabó Zsolt, Óbudai Egyetem, 2011 szabo. zsolt@nik. uni-obuda. hu 13
Nyelvi elemek • Lambda kifejezések: a programkód rövidítése miatt, hogy ne kelljen minden különféle szűréshez / sorrendezéshez / összegszámoláshoz külön delegate-et és metódust írni • var típus (C#3 -tól): egy metódusban deklarált változó típusának meghatározását a fordítóra bízzuk. Fontos lehet, ha annyira dinamikus az osztály, hogy fogalmunk sincs egy változó tényleges típusáról • Kötelező egyből értéket rendelni a var típusú változóhoz, innentől az úgy fog viselkedni, mint az ekvivalens típus V 1. 0 Szabó Zsolt, Óbudai Egyetem, 2011 szabo. zsolt@nik. uni-obuda. hu 14
Nyelvi elemek • Objektum inicializáló: ha van egy osztálynak nulla paraméteres konstruktora: diak bela = new diak() { kreditek = 23, nev = "Béla" }; • Névtelen osztályok: var Név. Kor. Cím = new { nev="Béla" , kor=23, cim="Budapest Bécsi út 96/B" }; V 1. 0 Szabó Zsolt, Óbudai Egyetem, 2011 szabo. zsolt@nik. uni-obuda. hu 15
Használható operátorok • Rendezés: Order. By – tetszőleges sorrend, Reverse – sorrend megfordítása • Halmaz-kezelés: Concat – egymás után másolás, Contains – elem meglétének vizsgálata, Distinct – ismétlések szűrése, Intersect – halmazelméleti metszet, Union – halmazelméleti únió, Except – Halmazelméleti különbség • Szűrés: Where • „Számolás” („Aggregate methods”, aggregáló eljárások): Average – átlag, Count – darabszám, Max – Maximum, Min – Minimum, Sum – Összeg • Csoportosítás: Group. By – valamilyen közös tulajdonság szerint lehet csoportosítani a tagokat • Mi ezeket egyszerű tömbökön / listákon fogjuk használni Szabó Zsolt, Óbudai Egyetem, 2011 V 1. 0 szabo. zsolt@nik. uni-obuda. hu 16
LINQ Operátorok 1. – Megfordítás • Tegyük fel, hogy a gyűjtemény alaptípusa int[], és egyszerűen szűrünk/ megfordítunk tudjuk, hogy a kimenet is int[] lesz • Kimeneti típusnak EKKOR SEM HASZNÁLHATÓ int[], mert a meghívandó eljárás általánosan van megírva, ugyanaz az eljárás hívódik meg minden típusú gyűjteményre Mindig IEnumerable<valami> vagy sima var típust használunk Tömbbé konvertálható: uj. To. Array(); uj. To. List(); var uj = elso. Reverse(); foreach (var akt in uj) { Console. Write(uj + ", "); } Console. Read. Line(); è 3, 2, 1, 2, 8, 6, 4, Szabó 2 Zsolt, Óbudai Egyetem, 2011 V 1. 0 szabo. zsolt@nik. uni-obuda. hu 17
LINQ Operátorok 2. – Halmazok • Elem létezésének vizsgálata: bool bennevan=elso. Contains(4); • Két gyűjtemény egymás után fűzése (NEM halmazok!): var uj = elso. Concat(masodik); • Ismétlődések kivágása (halmazzá alakítás): var uj = elso. Distinct(); • Halmazelméleti metszet: var uj = elso. Intersect(masodik); • Halmazelméleti únió: var uj = elso. Union(masodik); • Halmazelméleti különbség var uj = elso. Except(masodik); V 1. 0 Szabó Zsolt, Óbudai Egyetem, 2011 szabo. zsolt@nik. uni-obuda. hu 18
LINQ Operátorok 3. – Sorrendezés • Order. By – Paraméterül egy olyan eljárást vár, amely egy osztályból kiszedi a kulcsot (azt a mezőt, ami alapján rendezni fog) (Ehelyett egy lambda kifejezést szokás írni) – Második paraméterként megadható neki egy saját, IComparer interfészt implementáló osztály, ami az összehasonlítást végzi – Int tömb, rendezés az elemek alapján: var uj = elso. Order. By(x => x); – String tömb, rendezés az elemek hossza alapján: var uj = strtomb. Order. By(x => x. Length); – Diákok listája, névsorba rendezés : var uj = diakok. Order. By(x => x. nev); V 1. 0 Szabó Zsolt, Óbudai Egyetem, 2011 szabo. zsolt@nik. uni-obuda. hu 19
LINQ Operátorok 4. – Szűrés, darabszámolás • Where / Count – A paraméterül adott kifejezésnek bool típust kell visszaadni. – A Where eredménye az a gyűjtemény, ahol ez true értéket ad vissza. A Count eredménye a darabszám (int!!) – A count meghívható paraméter nélkül is teljes darabszám – Int tömb, a páratlanok: var uj = elso. Where(x => x % 2 == 0); – String tömb, a négy betűs nevek: int num = strtomb. Count(x => x. Length == 4); V 1. 0 Szabó Zsolt, Óbudai Egyetem, 2011 szabo. zsolt@nik. uni-obuda. hu 20
LINQ Operátorok 5. – Szűrés, részkiválasztás • Diákok listája, csak név: var uj = diakok. Select(x => x. nev); • Diákok listája, ahol a kreditszám prím: var uj = diakok. Where(x => { for (int i = 2; i <= Math. Sqrt(x. kreditek); i++) if (x. kreditek % i == 0) return false ; return true; }); // Második Miksa - 97, Negyedik Néró - 89 V 1. 0 Szabó Zsolt, Óbudai Egyetem, 2011 szabo. zsolt@nik. uni-obuda. hu 21
LINQ Operátorok 6. – Több operátor • Diákok listája, a páratlan kreditszámúak nagybetűs neve név szerinti fordított sorrendben: var uj = diakok. Where(x => x. kreditek%2==1). Order. By(x => x. nev). Reverse(). Select(x => x. nev. To. Upper()); // ÖTÖDIK ÖDÖN, NEGYEDIK NÉRÓ, MÁSODIK MIKSA • Ugyanaz az eredmény, ugyanaz a köztes kód: var uj = from x in diakok where x. kreditek % 2 == 1 orderby x. nev descending V 1. 0 select x. nev. To. Upper(); Szabó Zsolt, Óbudai Egyetem, 2011 szabo. zsolt@nik. uni-obuda. hu 22
LINQ Operátorok 7. – Aggregálás • Aggregáló metódusok int ossz = elso. Sum(); //28 double atlag = masodik. Average(); //2. 875 int paros. Ossz = elso. Where(x => x % 2 == 0). Sum(); //24 int paratlan. Ossz = elso. Where(x => x % 2 == 1). Sum(); //4 • A fenti példa gyakori: valamilyen ismétlődés szerint akarom csoportosítani a gyűjteményemet, és az egyes csoportokra szeretném tudni a darabszámot/összeget • Csoportonként egy where+aggregálás zavaró automata csoportosítás: Group. By V 1. 0 Szabó Zsolt, Óbudai Egyetem, 2011 szabo. zsolt@nik. uni-obuda. hu 23
LINQ Operátorok 8. – Csoportosítás • Csoportosítás, paritás szerinti darabszámok: var csoport=elso. Group. By(x => x % 2); foreach (var g in csoport) { Console. Write. Line( "Maradék: " + g. Key + ", darabszám: " + g. Count()); } var uj=from x in elso group x by x%2 into g select new {Maradek=g. Key, Darab=g. Count()}; V 1. 0 Szabó Zsolt, Óbudai Egyetem, 2011 szabo. zsolt@nik. uni-obuda. hu 24
Feladat • A meteorológiai szolgálat szuperszámítógépe előrejelzéseket készít az egész országra vonatkozólag • Az egyes előrejelzéseket az Elore. Jelzes osztály példányaiban tároljuk, az osztály adattagjai: dátum, régió {Eszak. Nyugat, Del. Nyugat, Eszak. Kozep, Del. Kozep, Eszak. Kelet, Del. Kelet}, jelleg {Napos, Kicsit. Felhos, Nagyon. Felhos, Esos, Viharos}, minimum hőmérséklet, maximum hőmérséklet • Generáljunk le véletlenszerűen a következő 100 nap előrejelzését • Lehessen szűrni régióra, időpontra • Mennyi a maximum és minimum hőmérséklet a 100 nap alatt; mennyi a keleti régiók átlaghőmérséklete; hány régióban lesz vihar • Mennyi az egyes régiók átlaghőmérséklete; melyik régióban van a legtöbbször napos idő Szabó Zsolt, Óbudai Egyetem, 2011 V 1. 0 szabo. zsolt@nik. uni-obuda. hu 25
Források • • • V 1. 0 Lambda expressions: http: //msdn. microsoft. com/en-us/library/bb 397687. aspx Lambda expressions: http: //geekswithblogs. net/michelotti/archive/2007/08/15/114702. aspx Why use Lambda expressions: http: //stackoverflow. com/questions/167343/c-lambda-expression -why-should-i-use-this Recursive lambda expressions: http: //blogs. msdn. com/b/madst/archive/2007/05/11/recursivelambda-expressions. aspx Standard query operators: http: //msdn. microsoft. com/en-us/library/bb 738551. aspx Linq introduction: http: //msdn. microsoft. com/library/bb 308959. aspx 101 Linq samples: http: //msdn. microsoft. com/en-us/vcsharp/aa 336746 Lambda: Reiter István: C# jegyzet (http: //devportal. hu/content/CSharpjegyzet. aspx) , 186 -187. oldal Linq: Reiter István: C# jegyzet (http: //devportal. hu/content/CSharpjegyzet. aspx) , 250 -269. oldal Szabó Zsolt, Óbudai Egyetem, 2011 szabo. zsolt@nik. uni-obuda. hu 26
V 1. 0 Szabó Zsolt, Óbudai Egyetem, 2011 szabo. zsolt@nik. uni-obuda. hu 27
- Slides: 28