Előadást letölteni
Az előadás letöltése folymat van. Kérjük, várjon
1
Lambda kifejezések LINQ
Haladó Programozás Lambda kifejezések LINQ Szabó Zsolt, Óbudai Egyetem, 2011
2
Lambda kifejezések LINQ
Haladó Programozás Lambda kifejezések LINQ Szabó Zsolt, Óbudai Egyetem, 2011
3
Szabó Zsolt, Óbudai Egyetem, 2011
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 A második pont lehetne akár nevesített metódussal is, így rövidebb Szabó Zsolt, Óbudai Egyetem, 2011
4
Szabó Zsolt, Óbudai Egyetem, 2011
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 Szabó Zsolt, Óbudai Egyetem, 2011
5
Szabó Zsolt, Óbudai Egyetem, 2011
Lambda kifejezések delegate int del(int i, int j); del myDelegate = (x, y) => x + y; int j = myDelegate(5, 10); //j = 15 Delegate nélkül is használható: Func<int, int> myFunc = (x) => x * x; int j = myFunc(5); //j = 25 Func<int, int, int> myFunc2 = (x, y) => x + y; int j = myFunc2(5, 10); //j = 15 A paraméterek típusozása nem kötelező, csak speciális esetekben Funct: utolsó helyen van a visszatérési típus, előtte a bemenő paraméterek (max. 4) A Func párja az Action, amely szintén maximum négy bemenő paramétert kaphat, de nem lehet visszatérési értéke Speciális eset: amikor a fordító nem tudja a delegate-ből eldönteni, hogy milyen típusúak a paraméterek Szabó Zsolt, Óbudai Egyetem, 2011
6
Szabó Zsolt, Óbudai Egyetem, 2011
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); Elmondani: * Func<inputtype, outputtype> * Unassigned variable, mert a Fakt definiálásához a Fakt-ot használom, de az még nincs definiálva Szabó Zsolt, Óbudai Egyetem, 2011
7
Szabó Zsolt, Óbudai Egyetem, 2011
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> Fakt2 = (f, x) => x == 1 ? 1 : x * f(f, x-1); j = Fakt2(Fakt2, 5); //j = 120 Ez a dia enyhén bonyolult, az elmondása legyen opcionális delegate int Recursive(Recursive r, int n); Elmondani: olyan delegate, ahol az első paraméter maga a delegate – vagyis, olyan függvényt lehet berakni, ahol az első paraméter egy ugyanolyan szignatúrájú függvény delegate KI Recursive<BE, KI>(Recursive<BE, KI> r, BE a); Elmondani: Olyan generikus delegate-et deklarálunk, amelynél két típust kell megadni: a be és a kimenet típusát. Ebbe a delegate-be olyan függvényeket tudok rakni, amelynek az első paramétere egy ugyanolyan delegate, a második paramétere a bemenet típusával azonos, a kimenete pedig a megadott kimeneti típussal Szabó Zsolt, Óbudai Egyetem, 2011
8
Szabó Zsolt, Óbudai Egyetem, 2011
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… Szabó Zsolt, Óbudai Egyetem, 2011
9
Lambda kifejezések LINQ
Haladó Programozás Lambda kifejezések LINQ Szabó Zsolt, Óbudai Egyetem, 2011
10
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) Üzleti logika réteg (OOP, PPT) Adat (erőforrás) réteg (ADB) A kép a PPT gyakorlatból származik © Szénási Sándor :) Az MVC elvről lehet mesélni egy kicsit Szabó Zsolt, Óbudai Egyetem, 2011
11
Szabó Zsolt, Óbudai Egyetem, 2011
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, VS2008SP1): 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 Elmondani: DLINQ nem használatos Szabó Zsolt, Óbudai Egyetem, 2011
12
Szabó Zsolt, Óbudai Egyetem, 2011
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 ToString() return nev + " - " + kreditek; Ezt a példa-osztályt fogjuk használni a példákban Szabó Zsolt, Óbudai Egyetem, 2011
13
Szabó Zsolt, Óbudai Egyetem, 2011
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)); Ezeket a gyűjteményeket fogjuk használni a példákban Szabó Zsolt, Óbudai Egyetem, 2011
14
Szabó Zsolt, Óbudai Egyetem, 2011
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 Szabó Zsolt, Óbudai Egyetem, 2011
15
Szabó Zsolt, Óbudai Egyetem, 2011
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évKorCím = new { nev="Béla", kor=23, cim="Budapest Bécsi út 96/B" }; A diák osztálynak nincs nulla paraméteres konstruktora, a fenti sor csak akkor működik, ha van! Szabó Zsolt, Óbudai Egyetem, 2011
16
Használható operátorok
Rendezés: OrderBy – 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: GroupBy – valamilyen közös tulajdonság szerint lehet csoportosítani a tagokat Mi ezeket egyszerű tömbökön / listákon fogjuk használni Esetleg elmondható: ezek az operátorok metódushívást jelentenek, és úgy oldják meg, hogy a már korábban is meglévő int[] típust visszafele kompatibilitás miatt nem módosítják, csak új metódusokat definiálnak a meglévő típushoz: C#3.0-tól van lehetőség kiterjesztett metódusok használatára: meglévő osztályhoz új metódusokat tudok csatolni (lásd Reiter István: C# jegyzet ( , 111. oldal Elmondani: csoportosítás működése: valami alapján csoportok képzése + csoportokon ugyanaz a művelet végrehajtása, gyakorlatilag where a csoportképző mező minden egyes értékére, és utána számolás Szabó Zsolt, Óbudai Egyetem, 2011
17
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.ToArray(); uj.ToList(); var uj = elso.Reverse(); foreach (var akt in uj) { Console.Write(uj + ", "); } Console.ReadLine(); 3, 2, 1, 2, 8, 6, 4, 2 Elmondani: IEnumerable<valami> , vagyis a LINQ operátorok kimenetéről általánosságban CSAK annyit tudunk, hogy foreach ciklussal bejárható, a feldolgozást is így végezzük. A foreach ciklus mindig ugyanilyen, a diákon ezentúl a foreach kimenete van csak feltüntetve Szabó Zsolt, Óbudai Egyetem, 2011
18
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); Elmondani: * Concat() esetén nincsenek kivágva az ismétlődések, csak sima egymás után másolás * halmazelméleti kifejezésnél automatikusan kivágja az ismétlődéseket Szabó Zsolt, Óbudai Egyetem, 2011
19
LINQ Operátorok 3. – Sorrendezés
OrderBy 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.OrderBy(x => x); String tömb, rendezés az elemek hossza alapján: var uj = strtomb.OrderBy(x => x.Length); Diákok listája, névsorba rendezés : var uj = diakok.OrderBy(x => x.nev); Második paraméter: nem fogjuk használni Elmondani: x=>x , Lambda kifejezés: bemenet=kimenet … Az „x” változóval fogjuk jelezni ezentúl az „atuális elem”-et Elmondani: a fordító meg az intellisense is ugyanúgy működik: érzékelik, hogy milyen gyűjteménynek hívom meg a metódusát. string[] esetén x=>x.Length jó, de x=>x.nev nem, ez utóbbi csak diak[] vagy List<diak> esetén jó Szabó Zsolt, Óbudai Egyetem, 2011
20
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); Második paraméter: nem fogjuk használni Elmondani: x=>x , Lambda kifejezés: bemenet=kimenet Elmondani: a fordító meg az intellisense is ugyanúgy működik: érzékelik, hogy milyen gyűjteménynek hívom meg a metódusát. string[] esetén x=>x.Length jó, de x=>x.nev nem, ez utóbbi csak diak[] vagy List<diak> esetén jó Szabó Zsolt, Óbudai Egyetem, 2011
21
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 Szabó Zsolt, Óbudai Egyetem, 2011
22
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). OrderBy(x => x.nev). Reverse(). Select(x => x.nev.ToUpper()); // Ö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 select x.nev.ToUpper(); Elmondani: NEM SQL! Azonos kulcsszavak, mert azonos feladatot látnak el, de más a sorrend, más a használat Szabó Zsolt, Óbudai Egyetem, 2011
23
LINQ Operátorok 7. – Aggregálás
Aggregáló metódusok int ossz = elso.Sum(); //28 double atlag = masodik.Average(); //2.875 int parosOssz = elso. Where(x => x % 2 == 0).Sum(); //24 int paratlanOssz = 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: GroupBy Szabó Zsolt, Óbudai Egyetem, 2011
24
LINQ Operátorok 8. – Csoportosítás
Csoportosítás, paritás szerinti darabszámok: var csoport=elso.GroupBy(x => x % 2); foreach (var g in csoport) { Console.WriteLine("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()}; Mondani: Csoportosításnál jobb a select-es kiírás Az eljáráshalmozás helyett is jobb a select-es kiírás A lambda kifejezések halmozása helyett is jobb a select-es kiírás Szabó Zsolt, Óbudai Egyetem, 2011
25
Szabó Zsolt, Óbudai Egyetem, 2011
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 EloreJelzes osztály példányaiban tároljuk, az osztály adattagjai: dátum, régió {EszakNyugat, DelNyugat, EszakKozep, DelKozep, EszakKelet, DelKelet}, jelleg {Napos, KicsitFelhos, NagyonFelhos, 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ő Az előrejelzéseket tároljuk listában! Szabó Zsolt, Óbudai Egyetem, 2011
26
Szabó Zsolt, Óbudai Egyetem, 2011
Források Lambda expressions: Lambda expressions: Why use Lambda expressions: Recursive lambda expressions: Standard query operators: Linq introduction: 101 Linq samples: Lambda: Reiter István: C# jegyzet ( , oldal Linq: Reiter István: C# jegyzet ( , oldal Szabó Zsolt, Óbudai Egyetem, 2011
27
Szabó Zsolt, Óbudai Egyetem, 2011
Hasonló előadás
© 2024 SlidePlayer.hu Inc.
All rights reserved.