13. diel - List
V minulej lekcii, Dátum a čas v C# - DateOnly a TimeOnly, sme si precvičili použitie štruktúr
DateOnly
a TimeOnly
.
Dnes si v C# tutoriále ukážeme jednu kolekciu, ktorá je múdrejší, než pole. Umožňuje totiž prvky ľubovoľne pridávať a mazať.
Pojem kolekcie sme tu už spomínali. Je to štruktúra, do ktorej môžeme
ukladať viacero objektov. Kolekcií je v .NET frameworku veľké množstvo, sú
prispôsobené na rôzne účely a môžeme s nimi zaobchádzať rôznymi
spôsobmi. Preto im je venovaný aj celý kurz Kolekcie a LINQ. Doteraz poznáme iba kolekciu
poľa. V priebehu kurzu však budeme potrebovať niečo múdrejšie, kam budeme
môcť jednoducho za behu programu pridávať a mazať
záznamy. Iste by sa nám hodilo si v pamäti spravovať databázu
nejakých objektov. Vieme, že pole má konštantnú veľkosť, čo je daň za
jeho vysokú rýchlosť. Teraz si predstavíme List
, ktorý
môžeme chápať ako nadstavbu poľa.
List
Zoznam (List
) je tzv. generická kolekcia.
Pojem genericita
si plne vysvetlíme až pri kolekciách, teraz nám bude stačiť vedieť, že
pri deklarácii zoznamu musíme špecifikovať dátový typ objektov, ktoré v
ňom budú uložené. Začnime jednoducho a urobme si List
čísel,
ktoré budeme náhodne žrebovať.
Žrebovanie
Program sa nás vždy spýta, či chceme žrebovať ďalšie číslo a to sa
pridá do zoznamu. Pokiaľ už nebudeme chcieť žrebovať, program vypíše
žrebované čísla, zoradené od najmenšieho po najväčšie. Založme si
nový projekt ListLottery
a vytvorme si triedu
Lottery
. Trieda bude obsahovať List
typu
int
, kde budú čísla uložené. List
bude privátny
a bude slúžiť iba ako interné úložisko danej triedy, aby sa naň zvonku
nedalo pristupovať. List
deklarujeme takto:
List<int> numbers;
Dátový typ píšeme pri generických kolekciách do špicatých
zátvoriek. List
je samozrejme objekt, ako každý iný.
Rovnako ako pri poli a iných objektoch, aj tu premennú pred použitím
inicializujeme:
List<int> numbers = new List<int>();
Všimnite si zátvorku, ktorú značí konštruktor. Takýto zoznam teda
umiestnime do našej triedy, spolu s náhodným generátorom
Random
. V konštruktore atribúty inicializujeme:
class Lottery { private List<int> numbers; private Random random; public Lottery() { random = new Random(); numbers = new List<int>(); } }
Ďalej pridáme metódy Lot()
a Print()
, kde
Lot()
pridá do zoznamu numbers
nové náhodné
číslo a tiež ho vráti ako návratovú hodnotu. Print()
vráti
textový reťazec na vypísanie. Ten bude obsahovať čísla z
numbers
, zoradené a oddelené medzerou.
Žrebovanie náhodného čísla už poznáme z lekcie
o hracej kocke, tu budeme vyhadzovať čísla od 1
do
100
. Číslo do kolekcie List
pridáme pomocou metódy
Add()
:
public int Lot() { int number = random.Next(100) + 1; numbers.Add(number); return number; }
Veľmi jednoduché, že? Kolekcia List
je interne pomerne
zložitá a zatiaľ sa nebudeme zaoberať tým, čo sa vo vnútri deje. To je
napokon účel .NET frameworku, ponúkať kvalitné a sofistikované komponenty,
ktoré sa jednoducho používajú.
Výpis čísel bude ešte jednoduchší. Na zotriedenie použijeme metódu
Sort()
volanú na inštanciu zoznamu, ktorá List
zotriedi. Je podobná metóde Sort()
na triede Array
.
Metóda nič nevracia, iba List
vo vnútri zotriedi:
public string Print() { string s = ""; numbers.Sort(); foreach (int i in numbers) s += i + " "; return s; }
Hotovo.
Presuňme sa do Main()
a pomocou while
cyklu
umožnime užívateľovi ovládať objekt. Podobný program bola kalkulačka z
prvých lekcií, kde sme sa v cykle pýtali, či si používateľ praje
opakovať výpočet. Tu budeme postupovať totožne.
Ovládanie bude pomocou možností 1, 2, 3 (losuj, vypíš, koniec). Budeme
ich načítať pomocou Console.ReadKey()
ako char
, nie
ako string
. Nezabudnite teda, že znaky zapisujeme pomocou
apostrofov, nie úvodzoviek:
Lottery lottery = new Lottery(); Console.WriteLine("Welcome to our lottery program."); char choice = '0'; // main loop while (choice != '3') { // option list Console.WriteLine("1 - Lot the next number"); Console.WriteLine("2 - Print numbers"); Console.WriteLine("3 - Quit"); choice = Console.ReadKey().KeyChar; Console.WriteLine(); // reaction to choice switch (choice) { case '1': Console.WriteLine("You got a: {0}", lottery.Lot()); break; case '2': Console.WriteLine("Numbers drawn: {0}", lottery.Print()); break; case '3': Console.WriteLine("Thanks for using our Lotto program"); break; default: Console.WriteLine("Invalid option. Please, try again."); break; } }
Priebeh programu je z kódu dobre viditeľný. Najprv nastavíme voľbu na
nejakú východiskovú hodnotu, aby cyklus prvýkrát prebehol. Potom voľbu
načítame z klávesnice ako znak. Znak spracujeme pomocou konštrukcie
switch
a vykonáme príslušné akcie. Pokiaľ bolo zadané niečo
iné, pokryje to možnosť default
:
Konzolová aplikácia
...
1 - Lot the next number
2 - Print numbers
3 - Quit
1
You got a: 52
1 - Lot the next number
2 - Print numbers
3 - Quit
1
You got a: 40
1 - Lot the next number
2 - Print numbers
3 - Quit
1
You got a: 62
1 - Lot the next number
2 - Print numbers
3 - Quit
2
Numbers drawn: 10 12 13 14 21 22 23 24 28 28 40 42 45 52 52 57 58 59 62 70 71 72 79 83 86 89
1 - Lot the next number
2 - Print numbers
3 - Quit
...
Vidíme, že môžeme stále pridávať nové a nové čísla. Máme oveľa väčšie možnosti, než s poľom. Zároveň však môžeme so zoznamom pracovať úplne rovnako, ako sme pracovali s poľom.
Môžeme používať indexáciu pomocou hranatých zátvoriek, ale pozor, prvok musí existovať. Skúsme si napísať nasledujúci kód:
List<string> l = new List<string>(); l.Add("First"); Console.WriteLine(l[0]); l[0] = "First item"; Console.WriteLine(l[0]); l[1] = "Second item"; // causes an error
Vytvoríme si List
položiek typu string
. Pridáme
položku First
a potom vypíšeme položku na indexe
0
. Vypíše sa nám First
. Môžeme na ňu samozrejme
aj takto zapisovať. S druhou položkou na pozícii 1
však už
nemôžeme pracovať, pretože sme ju do zoznamu nepridali. Pri poli sme zadali
veľkosť a on všetky "priehradky" (premenné pod indexy) založil. Teraz
veľkosť nezadávame a "priehradky" si pridávame sami.
Pozrime sa na List
podrobnejšie a vypíšme si metódy, ktoré
sú pre nás teraz zaujímavé:
Konštruktory
Okrem prázdneho zoznamu môžeme List
vytvoriť aj ako kópiu z
iného zoznamu, poľa alebo inej kolekcie. Stačí kolekciu odovzdať do
konštruktora:
{CSHARP_CONSOLE}
string[] stringArray = {"First", "Second", "Third"};
List<string> l = new List<string>(stringArray);
Console.WriteLine(l[2]);
{/CSHARP_CONSOLE}
Kód vyššie vypíše Third
. Prvky poľa sa do nového zoznamu
skopírujú. Rovnako môžeme odovzdať aj iný List
.
Vlastnosti kolekcie List
Count
- Funguje akoLength
na poli, vracia počet prvkov v kolekcii.
Metódy kolekcie List
Add(item)
- MetóduAdd()
sme si už vyskúšali, ako parameter berie položku, ktorú vloží na koniec zoznamu.AddRange(collection)
- Pridá do zoznamu viac položiek, napr. z poľa.Clear()
- Vymaže všetky položky v zoznamu.Contains(item)
- Vraciatrue
/false
podľa toho, čiList
obsahuje odovzdanú položku.CopyTo(array)
- Skopíruje položky do odovzdaného poľa. Môžeme pridať parameter štartovný index a počet prvkov.IndexOf(item)
- Vráti index prvého výskytu položky (ako pri poli). Vracia-1
pri neúspechu.Insert(index, item)
- Vloží položku na daný index (pozíciu) v zoznamu.InsertRange(index, collection)
- Vloží prvky danej kolekcie na daný index.LastIndexOf(item)
- Vracia index posledného výskytu položky. Vracia-1
pri neúspechu.Remove(item)
- Vymaže prvú nájdenú položku.RemoveAt(index)
- Vymaže položku na danom indexe.RemoveRange(index, count)
- Vymaže daný počet prvkov od zadaného indexu.Reverse()
- Funguje rovnako ako u poľa, obrátiList
tak, že je prvá položka posledná a naopak. Metóda nič nevracia, zmeny sa vykonajú priamo v danom zoznamu.Sort()
-Sort()
už tiež poznáme, zotriedi položky v zoznamu. Metóda opäť nič nevracia.ToArray()
- Skopíruje položky do poľa a to vráti.
Ďalšie metódy
List
poskytuje aj ďalšie metódy, ktoré poznáme z poľa:
Average()
- Vráti priemer z položiek akodouble
.Distinct()
- Vráti unikátne elementy.First()
- Vráti prvý element.Last()
- Vráti posledný element.Intersect(collection)
- Vráti prienik zoznamu so zadanou kolekciou.Union(collection)
- Vráti zjednotenie `zoznamu so zadanou kolekciou.Min()
- Vráti najmenší prvok.Max()
- Vráti najväčší prvok.Sum()
- Vráti súčet prvkov.Take(count)
- Vráti prvky od začiatku kolekcieList
.
Vidíme, že kolekcia List
toho dokáže oveľa viac, než pole.
Najväčšou výhodou je pridávanie a mazanie prvkov. Daň vo výkone je
zanedbateľná. V kurze s kolekciami zistíme, že List
má ešte
ďalšie metódy, ale zatiaľ na to nemáme skúsenosti.
Program pre ukladanie žrebovaných čísel bol zaujímavý, ale určite sa nám bude v budúcnosti hodiť ukladať skôr objekty, než čísla.
V nasledujúcom cvičení, Riešené úlohy k 12.-13. lekcii OOP v C# .NET, si precvičíme nadobudnuté skúsenosti z predchádzajúcich lekcií.
Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 4x (55.91 kB)
Aplikácia je vrátane zdrojových kódov v jazyku C#