9. diel - LINQ operátory 1
V predchádzajúcom kvíze, Kvíz - Slovníky, množiny, front, zásobník v C# .NET Kolekcia, sme si overili nadobudnuté skúsenosti z predchádzajúcich lekcií.
So základnou syntaxou LINQ dopytov sme už oboznámení. V niekoľkých lekciách si teraz popíšme čo všetko nám LINQ ponúka, teda metódy, presnejšie povedané operátory, ktoré môžete vo svojich dopytoch používať. Všetko si ukážeme na príkladoch. Niekoľko prvých príkladov bude opakovaním, s ďalšími nadobudne práca s LINQ nové rozmery.
Reštrikčné operátory
Výsledok dopytu môžeme nejako podmieniť a vybrať teda len dáta, ktoré
spĺňajú nejakú podmienku. Medzi reštrikčné operátory patrí nám už
známy where.
where
Operátor where umožňuje vybrať len tie dáta, ktoré
spĺňajú určitú podmienku. Z postupnosti čísel vyberieme tak, ktoré sú
väčšie ako 5:
{CSHARP_CONSOLE}
int[] numbers = { 3, 5, 8, 5, 9, 1, 3, 4 };
var query = from n in numbers
where (n > 5)
select n;
foreach (int number in query)
Console.WriteLine(number);
{/CSHARP_CONSOLE}
Dopyt vyberie:
Konzolová aplikácia
8
9
Všetky ďalšie príklady budú obsahovať rovnaký kód pre výpis výsledku, v článku ho už znova uvádzať nebudeme.
Indexované Where()
Čo sme si ešte neukazovali je použitie tzv. indexovaného
Where(), v ktorom môžeme pracovať s indexom prvku v kolekcii.
Vyberme čísla, ktoré majú rovnakú hodnotu ako ich index v poli:
{CSHARP_CONSOLE}
int[] numbers = { 0, 5, 2, 5, 4, 1, 3, 7 };
var query = numbers.Where((number, index) => number == index);
foreach (int number in query)
Console.WriteLine(number);
{/CSHARP_CONSOLE}
Dopyt vyberie:
Konzolová aplikácia
0
2
4
7
Použili sme tu mimochodom zápis dopytu cez metódy. Niektoré operátory inak zapísať nemožno a nepodporujú SQL-like zápis, budeme sa tu s nimi stretávať aj naďalej.
Projekčné operátory
S vybranými prvkami sa nemusíme uspokojiť tak, ako sú, ale môžeme z výsledných prvkov vybrať iba nejakú vlastnosť.
select
Pomocou select určíme čo konkrétne nás pri vybraných
prvkoch zaujíma. Nechajme si vrátiť dvojnásobky čísel väčších ako
5:
{CSHARP_CONSOLE}
int[] numbers = { 3, 5, 8, 5, 9, 1, 3, 4 };
var query = from n in numbers
where (n > 5)
select n * 2;
foreach (int number in query)
Console.WriteLine(number);
{/CSHARP_CONSOLE}
Dopyt vráti:
Konzolová aplikácia
16
18
Rovnako môžeme mapovať aj nejakú vlastnosť alebo výsledok metódy,
napr. Length alebo ToLower() na reťazci:
{CSHARP_CONSOLE}
string[] words = { "SOcial", "nEtwork", "ICTdemy" };
var query = from w in words
select w.ToLower();
foreach (string word in query)
Console.WriteLine(word);
{/CSHARP_CONSOLE}
Dopyt vyberie:
Konzolová aplikácia
social
network
ictdemy
Indexovaný Select()
s anonymnými typmi
Rovnako ako Where() aj u operátora Select() máme
prístup k indexu prvku. S anonymnými typmi sme sa zoznámili v minulej lekcii,
ukážme si teda, ako vybrať anonymný typ, obsahujúci pozíciu a hodnotu
daného prvku:
{CSHARP_CONSOLE}
int[] numbers = { 3, 5, 8, 5 };
var query = numbers.Select((number, index) => new { Index = index, Value = number });
foreach (var element in query)
Console.WriteLine(element);
{/CSHARP_CONSOLE}
Dopyt vyberie:
Konzolová aplikácia
{ Index = 0, Value = 3 }
{ Index = 1, Value = 5 }
{ Index = 2, Value = 8 }
{ Index = 3, Value = 5 }
Rozdeľujúce operácie
Pôvodnú kolekciu môžeme nejakým spôsobom rozdeliť a ďalej pracovať iba s jej časťou.
Take()
Take() vyberie niekoľko prvých prvkov z kolekcie a zvyšok
zahodí. Vyberme si iba prvé tri čísla z poľa:
{CSHARP_CONSOLE}
int[] numbers = { 3, 5, 8, 5, 9, 1, 3, 4 };
var query = numbers.Take(3);
foreach (int number in query)
Console.WriteLine(number);
{/CSHARP_CONSOLE}
Dopyt vyberie:
Konzolová aplikácia
3
5
8
Take() s dopyt
Take() môžeme zavolať aj na výsledku LINQ dopytu tak, že ho
ozátvorkujeme:
{CSHARP_CONSOLE}
int[] numbers = { 3, 5, 8, 5, 9, 1, 3, 4 };
var query = (from n in numbers
where (n > 3)
select n * 2).Take(3);
foreach (int number in query)
Console.WriteLine(number);
{/CSHARP_CONSOLE}
Dopyt vyberie:
Konzolová aplikácia
10
16
10
Skip()
Skip() je opačná funkcia k Take(), vyberie teda
všetky prvky okrem niekoľkých prvých, ktoré preskočí, od toho názov
operátora.
Vyberme z poľa všetky čísla okrem prvých piatich:
{CSHARP_CONSOLE}
int[] numbers = { 3, 5, 8, 5, 9, 1, 3, 4 };
var query = numbers.Skip(5);
foreach (int number in query)
Console.WriteLine(number);
{/CSHARP_CONSOLE}
Dopyt vyberie:
Konzolová aplikácia
1
3
4
Pomocou Skip() a Take() sa často rieši výber
náhodného prvku:
{CSHARP_CONSOLE}
int[] numbers = { 3, 5, 8, 5, 9, 1, 3, 4 };
Random r = new Random();
var query = numbers.Skip(r.Next(numbers.Length)).Take(1);
foreach (int number in query)
Console.WriteLine(number);
{/CSHARP_CONSOLE}
Dopyt vyberie jedno náhodné číslo z poľa.
Pri spustení online sa výsledok uloží do medzipamäte a bude to vyzerať, že padá stále to isté číslo. Obnovenie vyrovnávacej pamäte môžete vykonať zmenou zdrojového kódu, napr. pridaním nejakého komentára.
TakeWhile()
Prvky môžeme vyberať postupne od začiatku až do splnenia určitej
podmienky. Od tej chvíle pridávanie prvkov do výsledku prestane. Vyberme si
niekoľko čísel, ktoré sú väčšie ako 2:
{CSHARP_CONSOLE}
int[] numbers = { 3, 5, 8, 5, 9, 1, 3, 4 };
var query = numbers.TakeWhile(n => n > 2);
foreach (int number in query)
Console.WriteLine(number);
{/CSHARP_CONSOLE}
Dopyt vyberie:
Konzolová aplikácia
3
5
8
5
9
TakeWhile() môžeme tiež indexovať.
SkipWhile()
Analogicky existuje aj SkipWhile(), ktoré by čísla
preskakovalo pokiaľ platí určitá podmienka a až potom začne čísla do
výsledku pridávať. Preskočme niekoľko prvých čísel, ktoré sú väčšie
ako 2:
{CSHARP_CONSOLE}
int[] numbers = { 3, 5, 8, 5, 9, 1, 3, 4 };
var query = numbers.SkipWhile(n => n > 2);
foreach (int number in query)
Console.WriteLine(number);
{/CSHARP_CONSOLE}
Dopyt vyberie:
Konzolová aplikácia
1
3
4
SkipWhile() môžeme tiež indexovať.
Skip() môžeme (ako každú podobnú metódu) zavolať ako pri
príklade s Take() na dopyte tak, že ho ozátvorkujeme. To už
nebudem pri ďalších metódach uvádzať.
Radiace operátory
S OrderBy(), OrderByDescending(),
ThenBy() a ThenByDescending() sme sa už stretli.
Ukážme si ale, ako môžeme radiť pomocou comparera.
OrderBy() pomocou
IComparer
Použitie comparerov získava svoju výhodu vo chvíli, keď chceme dopyt parametrizovať a striedať kritériá, podľa ktorých triedime (necháme ich výber napr. na užívateľovi). Najprv je dôležité deklarovať si svoj comparer, v ukážke použijeme comparer textových reťazcov, ktorý porovnáva reťazce s ohľadom na veľké a malé písmená:
public class CaseSensitiveComparer : IComparer<string> { public int Compare(string x, string y) { return string.Compare(x, y, StringComparison.Ordinal); } }
Teraz comparer vložíme do dopytu:
{CSHARP_CONSOLE} string[] words = { "Argentina", "anaconda", "aLbert", "Buffalo", "business", "BOmb" }; var query = words.OrderBy(w => w, new CaseSensitiveComparer()); foreach (string word in query) Console.WriteLine(word); {/CSHARP_CONSOLE}{CSHARP_OOP} public class CaseSensitiveComparer : IComparer<string> { public int Compare(string x, string y) { return string.Compare(x, y, StringComparison.Ordinal); } } {/CSHARP_OOP}
Dopyt vyberie:
Konzolová aplikácia
Argentina
BOmb
Buffalo
aLbert
anaconda
business
Množinové operátory
Na kolekciu môžeme pozerať ako na množinu a použiť nasledujúce operátory, ktoré nám často zjednodušia prácu.
Distinct()
Distinct() odstráni duplicitné prvky a vráti jedinečné
hodnoty v poradí, v ktorom sa prvýkrát objavili v pôvodnom poli:
{CSHARP_CONSOLE}
int[] numbers = { 3, 5, 8, 5, 9, 1, 3, 4 };
var query = numbers.Distinct();
foreach (int number in query)
Console.WriteLine(number);
{/CSHARP_CONSOLE}
Dopyt vyberie:
Konzolová aplikácia
3
5
8
9
1
4
Union()
Union() vyberie množinové zjednotenie. Na vstupe sú teda dve
kolekcie a na výstupe množina (kolekcia) obsahujúca všetky prvky dvoch
vstupných kolekcií tak, že je každý obsiahnutý iba raz. Skúsme si to:
{CSHARP_CONSOLE}
int[] set1 = { 3, 5, 8, 5, 9, 1, 3, 4 };
int[] set2 = { 3, 7, 2, 1, 4 };
var query = set1.Union(set2);
foreach (int number in query)
Console.WriteLine(number);
{/CSHARP_CONSOLE}
Dopyt vyberie:
Konzolová aplikácia
3
5
8
9
1
4
7
2
Intersect()
Intersect() vyberie množinový prienik. Na vstupe sú teda dve
kolekcie a na výstupe množina (kolekcia) obsahujúca iba prvky, ktoré sú
obom vstupným kolekciám spoločné. Skúsme si to:
{CSHARP_CONSOLE}
int[] set1 = { 3, 5, 8, 5, 9, 1, 3, 4 };
int[] set2 = { 3, 7, 2, 1, 4 };
var query = set1.Intersect(set2);
foreach (int number in query)
Console.WriteLine(number);
{/CSHARP_CONSOLE}
Dopyt vyberie:
Konzolová aplikácia
3
1
4
Except()
Metóda Except() nám umožňuje vytvoriť postupnosť
obsahujúcu tie hodnoty z prvej množiny, ktoré sa nevyskytujú v množine
druhej:
{CSHARP_CONSOLE}
int[] set1 = { 3, 5, 8, 5, 9, 1, 3, 4 };
int[] set2 = { 3, 7, 2, 1, 4 };
var query = set1.Except(set2);
foreach (int number in query)
Console.WriteLine(number);
{/CSHARP_CONSOLE}
Dopyt vyberie:
Konzolová aplikácia
5
8
9
V nasledujúcom cvičení, Riešené úlohy k 7.-9. lekcii práce s kolekciami v C# .NET, si precvičíme nadobudnuté skúsenosti z predchádzajúcich lekcií.

David sa informačné technológie naučil na