9. díl - LINQ operátory 1

C# .NET Kolekce a LINQ LINQ operátory 1

V minulém dílu našeho seriálu tutoriálů o C# .NET 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 článcí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 nabyde 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

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;

Dotaz vybere:

8
9

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:

0
2
4
7

Použili jsme zde mimochodem zápis dotazu přes metody. Některé operátory jinak zapsat nelze a nemají podobu SQL-like zápisu, 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 dvoujná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:

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", "DevBOOk" };

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

Dotaz vybere:

socialni
sit
devbook

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ém dílu, 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:

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

Rozdělující operace

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:

3
5
8

Take s dotazem

Take můžeme zavolat i na výsledku běžného 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:

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:

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.

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:

3
5
8
5
9

TakeWhile můžeme také indexovat.

SkipWhile

Analogicky existuje i SkipWhile, které přeskakuje čísla 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:

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í Compareru

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());

Dotaz vybere:

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:

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:

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:

3
1
4

Except

Operátor 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:

5
8
9

Příště budeme pokračovat v popisu operátorů LINQu, uvidíte, že toho umí ještě hodně :)


 

  Aktivity (1)

Článek pro vás napsal David Čápka
Avatar
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 se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.

Jak se ti líbí článek?
Celkem (6 hlasů) :
4.833334.833334.833334.833334.83333


 


Miniatura
Všechny články v sekci
Kolekce v C# .NET a LINQ
Miniatura
Následující článek
LINQ operátory 2

 

 

Komentáře

Avatar
Posix
Člen
Avatar
Posix:

Ten LINQ vypadá hodně dobře, ještě se to naučit používat... Ale věřím, že to půjde. Na dobré věci se lehce zvyká... ne jak v C, kde se musí napsat tuna kódu a tady je to na jeden řádek :D

Odpovědět  +3 5.3.2013 22:50
Proč to dělat jednoduše, když to jde složitě.
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Posix
David Čápka:

Díky výkonu dnešních počítačů si můžeme určitý komfort dovolit a pracuje se s tím opravdu dobře :)

Odpovědět 6.3.2013 16:51
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
Kit
Redaktor
Avatar
Odpovídá na David Čápka
Kit:

Už se mi stalo, že jsem přepsal aplikaci z C do interpretru. Výrazně se zkrátila a zrychlila. Použití moderního jazyka tedy neznamená vždy zpomalení aplikace. Jen je nutné použít správné paradigma, na které je ten jazyk stavěný.

Odpovědět  +1 6.3.2013 16:58
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
j.c
Člen
Avatar
j.c:

Indexované where - příklad odtud:
///
int[] cisla1 = { 0, 5, 2, 5, 4, 1, 3, 7 };
var dotaz = cisla1.Where((cis­lo, index) => cislo == index);
foreach (int cokoli in dotaz)
{
Console.Write­Line(cokoli);
}
/// když ho takto zprzním
int[] cisla1 = { 0, 5, 2, 5, 4, 1, 3, 7 };
var dotaz = cisla1.Where((cys­lo, yndeks) => cyslo == yndeks);
foreach (int cokoli in dotaz)
{
Console.Write­Line(cokoli);

///chodí to furt, žádná deklarace, "samo" to pozná, co je cislo, index, to je zdrcující, čte to myšlenky, čičo? Můžeš to prosím aspoň trochu vysvětlit? Dík ;)

 
Odpovědět 22.12.2014 10:39
Avatar
lukas2901
Člen
Avatar
Odpovídá na j.c
lukas2901:

Tvoje rádoby zprznění je o čem ? na co se vlastně ptáš ?

 
Odpovědět 9.1.2015 16:05
Avatar
j.c
Člen
Avatar
Odpovídá na lukas2901
j.c:

"cislo" není deklarováno, a tuším, že kdybych zaměnil číslo a index, bude to dále stále chodit. A to mi přijde až příliš snadné ;).

 
Odpovědět 12.1.2015 8:49
Avatar
Daziko
Člen
Avatar
Odpovídá na j.c
Daziko:

Toto ti bude fungovat :

int[] cisla1 = { 0, 5, 2, 5, 4, 1, 3, 7 };
var dotaz = cisla1.Where((cyslo, yndeks) => cyslo == yndeks);
foreach (int cokoli in dotaz)
{
    Console.WriteLine(cokoli);
}

toto fungovat nebude :

int[] cisla1 = { 0, 5, 2, 5, 4, 1, 3, 7 };
var dotaz = cisla1.Where((cyslo, yndeks) => cislo == index);
foreach (int cokoli in dotaz)
{
    Console.WriteLine(cokoli);
}

cyslo a yndex definujes tu :

cisla1.Where((cyslo, yndeks)
 
Odpovědět  +2 12.1.2015 13:17
Avatar
pracansky
Člen
Avatar
Odpovídá na j.c
pracansky:

Řekl bych že to pozná to podle pořadí. Ten druhy je index a pojmenování vůbec nezáleží.
Vede mě k tomu i fakt že na druhé pozici očekává Int32

 
Odpovědět 12.4.2015 13:38
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 8 zpráv z 8.