Lekce 15 - List
V minulé lekci, Datum a čas v C# - DateOnly a TimeOnly, jsme si procvičili použití struktur
DateOnly a TimeOnly.
Dnes si v C# tutoriálu ukážeme jednu kolekci, která je chytřejší než pole. Umožňuje totiž prvky libovolně přidávat a mazat.
Pojem kolekce jsme tu již zmínili. Je to struktura, do které můžeme
ukládat více objektů. Kolekcí je v .NET frameworku velké množství, jsou
uzpůsobeny k různým účelům a můžeme s nimi zacházet různými způsoby.
Proto jim je věnován i celý kurz Kolekce a
LINQ. Dosud známe pouze kolekci pole. V průběhu kurzu však budeme
potřebovat něco chytřejšího, kam budeme moci jednoduše za běhu programu
přidávat záznamy a také je odtud mazat. Jistě by se nám
hodilo si v paměti spravovat databázi nějakých objektů. Víme, že pole má
konstantní velikost, což je daň za jeho vysokou rychlost. Nyní si
představíme List, který můžeme chápat jako nadstavbu
pole.
List
List je tzv. generická kolekce. Pojem genericita
si plně vysvětlíme až u kolekcí, nyní nám bude stačit vědět, že při
deklaraci kolekce List musíme specifikovat datový typ objektů,
které v ní budou uloženy. Začněme jednoduše. Vytvořme si
List čísel, která budeme náhodně losovat.
Losování
Program se nás vždy zeptá, zda chceme losovat další číslo. Číslo se
přidá do kolekce List. Pokud již nebudeme chtít losovat,
program vypíše losovaná čísla, seřazená od nejmenšího po největší.
Založme si nový projekt Losovani a vytvořme si třídu
Losovac. Třída bude obsahovat List typu
int, kde budou čísla uložena. List bude privátní
a bude sloužit pouze jako interní úložiště dané třídy, aby se k němu
zvenku nedalo přistupovat. List deklarujeme takto:
List<int> cisla;
Datový typ píšeme u generických kolekcí do špičatých
závorek. List je samozřejmě objekt jako každý jiný.
Stejně jako u pole a jiných objektů i zde proměnnou před použitím
inicializujeme:
List<int> cisla = new List<int>();
Všimněte si závorek, které značí konstruktor. Takovýto list tedy
umístíme do naší třídy spolu s náhodným generátorem
Random. V konstruktoru atributy inicializujeme:
class Losovac { private List<int> cisla; private Random random; public Losovac() { random = new Random(); cisla = new List<int>(); } }
Dále přidáme metody Losuj() a Vypis(), kde
Losuj() přidá do kolekce List nové náhodné
číslo a také ho vrátí jako návratovou hodnotu. Vypis()
vrátí textový řetězec pro vypsání. Ten bude obsahovat čísla z
cisla, a to seřazená a oddělená mezerou.
Losování náhodného čísla již známe z lekce
o hrací kostce, zde budeme vyhazovat čísla od 1 do
100. Číslo do kolekce List přidáme pomocí metody
Add():
public int Losuj() { int cislo = random.Next(100) + 1; cisla.Add(cislo); return cislo; }
Velmi jednoduché, že? Kolekce List je interně poměrně
složitá a zatím se nebudeme zabývat tím, co se uvnitř děje. To je
ostatně účel .NET frameworku, a sice nabízet kvalitní a sofistikované
komponenty, které se jednoduše používají.
Výpis čísel bude ještě snazší. K setřídění použijeme metodu
Sort() na kolekci List, která list
setřídí. Je podobná metodě Sort() na třídě
Array. Metoda nic nevrací, pouze List uvnitř
setřídí.
public string Vypis() { string s = ""; cisla.Sort(); foreach (int i in cisla) s += i + " "; return s; }
Hotovo.
Přesuňme se do Main() a pomocí while cyklu
umožněme uživateli ovládat objekt. Podobným programem byla kalkulačka z
prvních lekcí, kde jsme se v cyklu ptali, zda si uživatel přeje opakovat
výpočet. Zde budeme postupovat totožně.
Ovládat program budeme pomocí možností 1, 2, 3 (losuj, vypiš, konec).
Možnosti budeme načítat pomocí Console.ReadKey() jako
char, nikoli jako string. Nezapomeňme tedy, že znaky
zapisujeme pomocí apostrofů, nikoli uvozovek.
Losovac losovac = new Losovac(); Console.WriteLine("Vítejte v programu losování."); char volba = '0'; // hlavní cyklus while (volba != '3') { // výpis možností Console.WriteLine("1 - Losovat další číslo"); Console.WriteLine("2 - Vypsat čísla"); Console.WriteLine("3 - Konec"); volba = Console.ReadKey().KeyChar; Console.WriteLine(); // reakce na volbu switch (volba) { case '1': Console.WriteLine("Padlo číslo: {0}", losovac.Losuj()); break; case '2': Console.WriteLine("Padla čísla: {0}", losovac.Vypis()); break; case '3': Console.WriteLine("Děkuji za použití programu"); break; default: Console.WriteLine("Neplatná volba, zadejte prosím znovu."); break; } }
Průběh programu je z kódu dobře viditelný. Nejprve nastavíme volbu na
nějakou výchozí hodnotu, aby cyklus poprvé proběhl. Poté volbu načteme z
klávesnice jako znak. Znak zpracujeme pomocí příkazu switch a
provedeme příslušné akce. Pokud bylo zadáno něco jiného, pokryje to
možnost default:.
Konzolová aplikace
3 - Konec
1
Padlo číslo: 52
1 - Losovat další číslo
2 - Vypsat čísla
3 - Konec
1
Padlo číslo: 40
1 - Losovat další číslo
2 - Vypsat čísla
3 - Konec
1
Padlo číslo: 62
1 - Losovat další číslo
2 - Vypsat čísla
3 - Konec
2
Padla čísla: 2 6 7 7 8 8 9 9 10 10 12 14 17 19 19 21 23 25 25 27 27 27 28 28 28 30 30 31 32 33 33 35 35 36 36 36 37 38 38 40 41 42 42 42 44 45 45 45 45 45 48 51 52 52 53 55 56 56 56 57 58 58 59 61 62 66 68 68 71 72 73 73 74 76 82 83 84 84 85 87 88 88 89 90 90 91 93 94 98 98 98 99 100
1 - Losovat další číslo
2 - Vypsat čísla
3 - Konec
Vidíme, že můžeme stále přidávat nová a nová čísla. Máme mnohem
větší možnosti než s polem. Zároveň však můžeme s kolekcí
List pracovat úplně stejně, jako jsme pracovali s polem.
Můžeme používat indexaci pomocí hranatých závorek, ale pozor, prvek musí existovat. Zkusme si napsat následující kód:
List<string> l = new List<string>(); l.Add("První"); Console.WriteLine(l[0]); l[0] = "První položka"; Console.WriteLine(l[0]); l[1] = "Druhá položka"; // způsobí chybu
Vytvoříme si List řetězců string. Přidáme
položku "První" a poté vypíšeme položku na indexu 0. Vypíše
se nám "První". Můžeme na ni samozřejmě takto i zapisovat. S druhou
položkou na pozici 1 však již pracovat nemůžeme, protože jsme
ji do listu nepřidali. U pole jsme zadali velikost a všechny "přihrádky"
(proměnné pod indexy) se založily. Nyní velikost nezadáváme a
"přihrádky" si přidáváme sami.
Podívejme se na List podrobněji a vypišme si metody, které
jsou pro nás nyní zajímavé:
Konstruktory
Kolekci List můžeme vytvořit nejen jako prázdný list, ale i
jako kopii z jiného listu, pole nebo jiné kolekce. Stačí kolekci předat do
konstruktoru:
{CSHARP_CONSOLE}
string[] poleStringu = {"První", "Druhá", "Třetí"};
List<string> l = new List<string>(poleStringu);
Console.WriteLine(l[2]);
{/CSHARP_CONSOLE}
Kód výše vypíše "Třetí". Prvky pole se do nového listu zkopírují.
Stejně můžeme předat i jiný List.
Vlastnosti na listu
Count– Funguje jakoLengthna poli, vrací počet prvků v kolekci.
Metody na listu
Add(položka)– MetoduAdd()jsme si již vyzkoušeli, jako parametr bere položku, kterou vloží na konec listu.AddRange(kolekce)– Přidá do listu více položek, např. z pole.Clear()– Vymaže všechny položky v listu.Contains(položka)– Vracítrue/falsepodle toho, zdaListobsahuje předanou položku.CopyTo(pole)– Zkopíruje položky do předaného pole. Můžeme přidat parametr startovní index a počet prvků.IndexOf(položka)– Vrátí index prvního výskytu položky (jako u pole). Vrací-1při neúspěchu.Insert(index, položka)– Vloží položku na daný index (pozici) v listu.InsertRange(index, kolekce)– Vloží prvky dané kolekce na daný index v listu.LastIndexOf(položka)– Vrací index posledního výskytu položky v listu. Vrací-1při neúspěchu.Remove(položka)– Vymaže první nalezenou položku.RemoveAt(index)– Vymaže položku na daném indexu.RemoveRange(index, počet)– Vymaže daný počet prvků od zadaného indexu.Reverse()– Funguje stejně jako u pole, obrátíListtak, že je první položka poslední a naopak. Metoda nic nevrací, změny se provedou přímo v kolekciList.Sort()–Sort()již také známe, setřídí položky v listu. Metoda opět nic nevrací.ToArray()– Zkopíruje položky z listu do pole a to vrátí.
Další metody
List poskytuje i další metody, které známe z pole:
Average()– Vrátí průměr z položek v listu jakodouble.Distinct()– Vrátí unikátní elementy z listu.First()– Vrátí první element.Last()– Vrátí poslední element.Intersect(kolekce)– Vrátí průnik listu se zadanou kolekcí.Union()– Vrátí sjednocení listu se zadanou kolekcí.Min()– Vrátí nejmenší prvek.Max()– Vrátí největší prvek.Sum()– Vrátí součet prvků.Take(počet)– Vrátí prvky od začátku kolekceList.
Vidíme, že kolekce List toho umí mnohem více než pole.
Největší výhodou je přidávání a mazání prvků. Daň v podobě
nižšího výkonu je zanedbatelná. V kurzu s kolekcemi zjistíme, že
List má ještě další metody, ale na ty zatím nemáme dostatek
zkušeností.
Program pro ukládání losovaných čísel byl zajímavý, ale jistě se nám bude v budoucnu hodit ukládat spíše objekty než čísla.
V následujícím cvičení, Řešené úlohy k 14.-15. lekci OOP v C# .NET, si procvičíme nabyté zkušenosti z předchozích lekcí.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 964x (26.67 kB)
Aplikace je včetně zdrojových kódů v jazyce C#


David se informační technologie naučil na