Lekce 13 - 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 jakoLength
na 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
/false
podle toho, zdaList
obsahuje 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í-1
př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í-1
př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íList
tak, ž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 12.-13. 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 929x (26.67 kB)
Aplikace je včetně zdrojových kódů v jazyce C#