BF Summer sales
Pouze tento týden sleva až 80 % na HTML & CSS a JavaScript
80 % bodů zdarma na online výuku díky naší Letní akci!

Lekce 9 - LINQ operátory 1

V minulé lekci, LINQ provideři, anonymní typy, řazení a seskupování, jsme se v LINQ naučili anonymní typy a ukázali si základy řazení a seskupování.

Se základní syntaxí LINQ dotazů jsme již tedy obeznámeni. V několika lekcích si nyní popišme co vše nám LINQ nabízí, tedy metody, přesněji řečeno operátory, které můžete ve svých dotazech používat. Vše si ukážeme na příkladech. Prvních několik příkladů bude opakováním, s dalšími nabude práce s LINQ nových rozměrů.

Restrikční operátory

Výsledek dotazu můžeme nějak podmínit a vybrat tedy jen data, která splňují nějakou podmínku. Mezi restrikční operátory patří nám již známé where.

where

Operátor where umožňuje vybrat jen ta data, která splňují určitou podmínku. Z posloupnosti čísel vybereme tak, která jsou větší než 5:

int[] cisla = { 3, 5, 8, 5, 9, 1, 3, 4 };

var dotaz = from c in cisla
            where (c > 5)
            select c;

foreach (int c in dotaz)
    Console.WriteLine(c);

Dotaz vybere:

Konzolová aplikace
8
9

Všechny další příklady budou obsahovat stejný kód pro výpis výsledku, v článku jej již znovu uvádět nebudeme.

Indexované Where()

Co jsme si ještě neukazovali je použití tzv. indexovaného Where(), ve kterém můžeme pracovat s indexem prvku v kolekci. Vyberme čísla, která mají stejnou hodnotu jako jejich index v poli:

int[] cisla = { 0, 5, 2, 5, 4, 1, 3, 7 };

var dotaz = cisla.Where((cislo, index) => cislo == index);

Dotaz vybere:

Konzolová aplikace
0
2
4
7

Použili jsme zde mimochodem zápis dotazu přes metody. Některé operátory jinak zapsat nelze a nepodporují SQL-like zápis, budeme se tu s nimi setkávat i nadále.

Projekční operátory

S vybranými prvky se nemusíme spokojit tak, jak jsou, ale můžeme z výsledných prvků vybrat pouze nějakou vlastnost.

select

Pomocí select určíme co konkrétně nás u vybraných prvků zajímá. Nechme si vrátit dvojnásobky čísel větších než 5:

int[] cisla = { 3, 5, 8, 5, 9, 1, 3, 4 };

var dotaz = from c in cisla
            where (c > 5)
            select c * 2;

Dotaz vybere:

Konzolová aplikace
16
18

Stejně tak můžeme mapovat i nějakou vlastnost nebo výsledek metody, např. Length nebo ToLower() na řetězci:

string[] slova = { "SOcialNi", "SiT", "ITnetWOrk" };

var dotaz = from s in slova
            select s.ToLower();

Dotaz vybere:

Konzolová aplikace
socialni
sit
itnetwork

Indexovaný Select() s anonymními typy

Stejně jako Where() i u operátoru Select() máme přístup k indexu prvku. S anonymními typy jsme se seznámili v minulé lekci, ukažme si tedy, jak vybrat anonymní typ, obsahující pozici a hodnotu daného prvku:

int[] cisla = { 3, 5, 8, 5 };

var dotaz = cisla.Select((cislo, index) => new { Index = index, Hodnota = cislo });

Dotaz vybere:

Konzolová aplikace
{ Index = 0, Hodnota = 3 }
{ Index = 1, Hodnota = 5 }
{ Index = 2, Hodnota = 8 }
{ Index = 3, Hodnota = 5 }

Rozdělující operace

Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!

Původní kolekci můžeme nějakým způsobem rozdělit a dále pracovat pouze s její částí.

Take()

Take vybere prvních několik prvků z kolekce a zbytek zahodí. Vyberme si pouze první 3 čísla z pole:

int[] cisla = { 3, 5, 8, 5, 9, 1, 3, 4 };

var dotaz = cisla.Take(3);

Dotaz vybere:

Konzolová aplikace
3
5
8

Take() s dotazem

Take() můžeme zavolat i na výsledku LINQ dotazu tak, že ho ozávorkujeme:

int[] cisla = { 3, 5, 8, 5, 9, 1, 3, 4 };

var dotaz = (from c in cisla
             where (c > 3)
             select c * 2).Take(3);

Dotaz vybere:

Konzolová aplikace
10
16
10

Skip()

Skip() je opačná funkce k Take(), vybere tedy všechny prvky kromě několika prvních, které přeskočí, od toho název operátoru.

Vyberme z pole všechna čísla kromě 5ti prvních:

int[] cisla = { 3, 5, 8, 5, 9, 1, 3, 4 };

var dotaz = cisla.Skip(5);

Dotaz vybere:

Konzolová aplikace
1
3
4

Pomocí Skip() a Take() se často řeší výběr náhodného prvku:

int[] cisla = { 3, 5, 8, 5, 9, 1, 3, 4 };
Random r = new Random();

var dotaz = cisla.Skip(r.Next(cisla.Length)).Take(1);

Dotaz vybere 1 náhodné číslo z pole.

Při spuštění online se výsledek uloží do mezipaměti a bude to vypadat, že padá stále to samé číslo. Obnovení mezipaměti můžete provést změnou zdrojového kódu, např. přidáním nějakého komentáře.

TakeWhile()

Prvky můžeme vybírat postupně od začátku až do splnění určité podmínky. Od té chvíle přidávání prvků do výsledku ustane. Vyberme si prvních několik čísel, které jsou větší než 2:

int[] cisla = { 3, 5, 8, 5, 9, 1, 3, 4 };

var dotaz = cisla.TakeWhile(c => c > 2);

Dotaz vybere:

Konzolová aplikace
3
5
8
5
9

TakeWhile() můžeme také indexovat.

SkipWhile()

Analogicky existuje i SkipWhile(), které by čísla přeskakovalo dokud platí určitá podmínka a až poté začne čísla do výsledku přidávat. Přeskočme prvních několik čísel, která jsou větší než 2:

int[] cisla = { 3, 5, 8, 5, 9, 1, 3, 4 };

var dotaz = cisla.SkipWhile(c => c > 2);

Dotaz vybere:

Konzolová aplikace
1
3
4

SkipWhile() můžeme rovněž indexovat.

Skip() můžeme (jako každou podobnou metodu) zavolat jako u příkladu s Take() na dotazu tak, že ho ozávorkujeme. Toto již nebudu u dalších metod uvádět.

Řadící operátory

S OrderBy(), OrderByDescending(), ThenBy() a ThenByDescending() jsme se již setkali. Ukažme si ale, jak můžeme řadit pomocí Compareru.

OrderBy() pomocí IComparer

Použití comparerů získává svou výhodu ve chvíli, kdy chceme dotaz parametrizovat a střídat kritéria podle kterých třídíme (necháme jejich výběr např. na uživateli). Nejprve je důležité deklarovat si svůj comparer, v ukázce použijeme comparer stringů, který porovnává stringy s ohledem na velká a malá písmena:

public class CaseSensitiveComparer : IComparer<string>
{
    public int Compare(string x, string y)
    {
        return string.Compare(x, y, StringComparison.Ordinal);
    }
}

Nyní comparer vložíme do dotazu:

string[] slova = { "Argentina", "anakonda", "aLbert", "Bizon", "brčál", "BOmba" };

var dotaz = slova.OrderBy(s => s, new CaseSensitiveComparer());
public class CaseSensitiveComparer : IComparer<string>
{
    public int Compare(string x, string y)
    {
        return string.Compare(x, y, StringComparison.Ordinal);
    }
}

Dotaz vybere:

Konzolová aplikace
Argentina
BOmba
Bizon
aLbert
anakonda
brčál

Množinové operátory

Na kolekci můžeme nahlížet jako na množinu a použít následující operátory, které nám často zjednoduší práci:

Distinct()

Distinct() vybere z kolekce pouze unikátní elementy. Vyberme tedy pouze unikátní čísla z pole:

int[] cisla = { 3, 5, 8, 5, 9, 1, 3, 4 };

var dotaz = cisla.Distinct();

Dotaz vybere:

Konzolová aplikace
3
5
8
9
1
4

Union()

Union() vybere množinové sjednocení. Na vstupu jsou tedy 2 kolekce a na výstupu množina (kolekce) obsahující všechny prvky 2 vstupních kolekcí tak, že je každý obsažen pouze jednou. Zkusme si to:

int[] mnozina1 = { 3, 5, 8, 5, 9, 1, 3, 4 };
int[] mnozina2 = { 3, 7, 2, 1, 4 };

var dotaz = mnozina1.Union(mnozina2);

Dotaz vybere:

Konzolová aplikace
3
5
8
9
1
4
7
2

Intersect()

Intersect() vybere množinový průnik. Na vstupu jsou tedy 2 kolekce a na výstupu množina (kolekce) obsahující pouze prvky které jsou oběma vstupním kolekcím společné. Zkusme si to:

int[] mnozina1 = { 3, 5, 8, 5, 9, 1, 3, 4 };
int[] mnozina2 = { 3, 7, 2, 1, 4 };

var dotaz = mnozina1.Intersect(mnozina2);

Dotaz vybere:

Konzolová aplikace
3
1
4

Except()

Metoda Except() nám umožňuje vytvořit posloupnost obsahující ty hodnoty z první množiny, které se nevyskytují v množině druhé.

int[] mnozina1 = { 3, 5, 8, 5, 9, 1, 3, 4 };
int[] mnozina2 = { 3, 7, 2, 1, 4 };

var dotaz = mnozina1.Except(mnozina2);

Dotaz vybere:

Konzolová aplikace
5
8
9

V příští lekci, LINQ operátory 2, budeme pokračovat v popisu operátorů LINQu, uvidíte, že toho umí ještě hodně :).


 

Předchozí článek
LINQ provideři, anonymní typy, řazení a seskupování
Všechny články v sekci
Kolekce a LINQ v C# .NET
Článek pro vás napsal David Čápka
Avatar
Jak se ti líbí článek?
12 hlasů
Autor pracuje jako softwarový architekt a pedagog na projektu ITnetwork.cz (a jeho zahraničních verzích). Velmi si váží svobody podnikání v naší zemi a věří, že když se člověk neštítí práce, tak dokáže úplně cokoli.
Unicorn College Autor sítě se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity (10)

 

 

Komentáře
Zobrazit starší komentáře (8)

Avatar
Patrik Pastor:29.4.2019 22:07

Jak to, ze se u .SkipWhile vypise vysledek :

1
3
4

kdyz je podmicka c > 2, potom by 3, 4 mel preskocit a vypsat pouze 1ku ne?

 
Odpovědět
29.4.2019 22:07
Avatar
Ondřej Štorc
Redaktor
Avatar
Odpovídá na Patrik Pastor
Ondřej Štorc:29.4.2019 23:36

Ne, skipuje v tom seznam dokud platí ta podmínka. Takže to vlastně vrátí tu kolekci od toho bodu, kdy ta podmínka poprvé přestala platit

Odpovědět
29.4.2019 23:36
Život je příliš krátký na to, abychom bezpečně odebírali USB z počítače..
Avatar
Patrik Pastor:29.4.2019 23:45

co je tenot enum: StringCompari­son.Ordinal? Hledal jsem to v dokumentaci, naslo mi to pouze, ze to radi (porovnava) string podle binarnich pravidel, Ale nechapu jak autori docilili caseSensitive - tedy ze to radi podle velikosti pismen (neni to z podminky zrejme).

 
Odpovědět
29.4.2019 23:45
Avatar
Patrik Pastor:29.4.2019 23:49

Souhlasim s tebou, ctu zde mnoho clanku a bavi me a jsou super, ale autori nekdy neco nedovysvetli, nereknou, nebo to berou jako samozrejmost (pravdepodobne predpokladji nejake zaklady, nebo si to jinak nedovedu vysvetlit). Tim nechci rict, ze by se mi to nelibilo, to bych si nekupoval clanky, stale ale je to "ceska" dokumentace a ta nikdy nebude tak kvalitni jako dokumentace zahranicni (nejlepe od zdroje).

Editováno 29.4.2019 23:49
 
Odpovědět
29.4.2019 23:49
Avatar
Odpovídá na Ondřej Štorc
Patrik Pastor:30.4.2019 0:20

aha dik, sem myslel ze ta podminka o preskoceni plati pro cely seznam. dik

 
Odpovědět
30.4.2019 0:20
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
Ondřej Štorc
Redaktor
Avatar
Odpovídá na Patrik Pastor
Ondřej Štorc:30.4.2019 8:46

No to ordinal to bere podle číselné reprezantace těch písmen. A minimálně pro anglickou abecedu platí, ze velká písmena mají nižší hodnotu než malá (tedy jsou v ASCII tabulce před malými)

Odpovědět
30.4.2019 8:46
Život je příliš krátký na to, abychom bezpečně odebírali USB z počítače..
Avatar
Odpovídá na Ondřej Štorc
Patrik Pastor:30.4.2019 10:50

chapu ze to v metode "compare(string x, string y)" porovnava. Nechapu ale, jak ty argumenty do te metody dostane touto podminkoub(s => s, new CaseSensitive())

 
Odpovědět
30.4.2019 10:50
Avatar
Ondřej Štorc
Redaktor
Avatar
Odpovídá na Patrik Pastor
Ondřej Štorc:30.4.2019 15:20

Je to kvůli tomu, že CaseSensitive­Comparer implementuje interface IComparer<string> a ta metoda OrderBy v jedné své variantě přímá jako druhý parametr instanci typu IComparer<T> (což nečekaně ten CaseSensitive­Comparer je...) viz. MS Doc A ohledně interfaců se dozvíš víc třeba ve zdejší sekci o OOP (v podstatě to řiká, že když ta třída implementuje interface, tak musí nějak implementovat ty metody co ten interface má)

Odpovědět
30.4.2019 15:20
Život je příliš krátký na to, abychom bezpečně odebírali USB z počítače..
Avatar
Odpovídá na Ondřej Štorc
Patrik Pastor:30.4.2019 16:13

chapu, rozumim i interfacum, nevedel jsem akoart ze metoda OrderaBy prijima instanci compareru.

 
Odpovědět
30.4.2019 16:13
Avatar
David Holohlavský:12. května 19:52

Díky za článek. ;-)

 
Odpovědět
12. května 19:52
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 18. Zobrazit vše