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 dotazov 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 dotazoch používať. Všetko si ukážeme na príkladoch. Prvých niekoľko príkladov bude opakovaním, s ďalšími nadobudne práca s LINQ nových rozmerov.
Reštrikčné operátory
Výsledok dotazu 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áme 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}
Dotaz 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}
Dotaz vyberie:
Konzolová aplikácia
0
2
4
7
Použili sme tu mimochodom zápis dotazu 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}
Dotaz vrátí:
Konzolová aplikácia
16
18
Rovnako tak 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}
Otázka 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}
Dotaz 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 prvých niekoľko 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}
Dotaz vyberie:
Konzolová aplikácia
3
5
8
Take()
s dotazom
Take()
môžeme zavolať aj na výsledku LINQ dotazu tak, že ho
ozátvoríme:
{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}
Dotaz 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čia, 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}
Dotaz 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}
Dotaz 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 ustane. Vyberme si
prvých 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}
Dotaz 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 prvých niekoľko čí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}
Dotaz 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 dotaze tak, že ho ozátvoríme. Toto už
nebudem u ďalších metód 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 dotaz 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 dotazu:
{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}
Dotaz 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}
Dotaz 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}
Dotaz 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}
Dotaz 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}
Dotaz 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í.