Programujeme v jazyku C# II. Diel 6. – Generics II

Michal Čižmár  /  01. 02. 2006, 00:00

V tomto dieli sa budeme zaoberať praktickým použitím Generics a ukážeme si základné triedy, ktoré nám umožňujú prácu so zoznamami, zásobníkmi, frontami, poliami atď...

Dúfam, že Vás poteší tento nový diel, ktorý vychádza po dlhšej odmlke, za ktorú sa ospravedlňujem. Mal som dosť roboty, ale teraz som už oddýchnutý a plný elánu v pokračovaní série o programovaní v C# v2.0.


V minulom dieli sme si v jednoduchosti vysvetlili podstatu Generics. Ako som už spomínal, veľa tried vhodných na zoznamy (diel 4. séria 2) je v C# implementovaných pomocou Generics a dajú sa veľmi ľahko a dosť efektívne použiť.


Postupne si prejdeme jednotlivé triedy, pozrieme sa na ich klady, zápory a čo je hlavné : oblasti použitia. Tento diel alebo možno aj budúci bude vo forme kuchárky, preto je tu hlavne veľa príkladov a už menej teórie.


>> List class - Zoznam
Začínam s touto triedou, pretože patri medzi najpraktickejšie. Umožňuje nám jednoducho vytvárať jednorozmerné polia, bez toho aby sme si sami museli písať funkcie pre indexový operátor []. Túto triedu rozoberiem podrobnejšie, aby sme si ukázali niektoré zaujímavé funkcie, ktoré majú aj ostatné podobné triedy, o ktorých budem hovoriť.


Príklad 6.1
using System;
using System.Collections.Generic; // Nezabudnut pridat !!
//----------------------------------------------------

class MainClass
{

public static void Main(string[] args)
{

// Vytvorenie zoznamu
List<string> mena = new List<string>();
//Naplnenie zoznamu
mena.Add("Jano");

mena.Add("Lucia");

mena.Add("Imro");

mena.Add("Diana");

//Vypis pomocou indexu
for(int i = 0; i < mena.Count; i++)
Console.WriteLine(mena[i]);

// Vlozenie noveho prvku na lubovolne miesto
// Indexuje sa od nuly,index 2 == 3 pozicia
Console.WriteLine("\nPridame Ivana na 3. miesto");
mena.Insert(2,"Ivan");

for(int i = 0; i < mena.Count; i++)
Console.WriteLine(mena[i]);

Console.WriteLine();

// Ak prvok nenajde vrati -1
int pos = mena.IndexOf("Fero");
Console.WriteLine("Fero je na pozicii s indexom : {0}",pos);
pos = mena.IndexOf("Imro");
Console.WriteLine("Imro je na pozicii s indexom : {0}",pos);
// Odstranenie prvku z lubovolnej pozicie
// Konkretne Imra

Console.WriteLine("\nOdstranime prvok s indexom {0}",pos);
mena.RemoveAt(pos);

for(int i = 0; i < mena.Count; i++)
Console.WriteLine(mena[i]);

//Vymazanie zoznamu
mena.Clear();

//Pozastavnie vypisu
Console.ReadLine();

}

}

//----------------------------------------------------
Príklad na stiahnutie





Príklad je podľa mňa dostatočne okomentovaný a ukazuje základné operácie s triedou List.


>>Časová náročnosť pridania nového prvku
Takáto pohodlná práca so zoznamom je zaplatená väčšou časovou náročnosťou na jeho spravovanie. Aby sme tento čas, čo najviac skrátili, je dobré vedieť
ako vnútorne trieda List funguje.


1. Pri vytvorení prázdneho zoznamu si vnútorne rezervuje klasické pole o konštantnej dĺžke.
2. Ak pridávame nový prvok pomocou .Add a nie sú ešte všetky políčka obsadené, všetko je v pohode a táto operácia trvá 1 časovú jednotku.
3. Ak už ale vo vnútornom poli nie je miesto, tak sa vytvorí nové pole s väčšou dĺžkou a všetky už uložené prvky sa doň ho skopírujú + nový prvok. A nakoniec sa staré pole zruší.
Ak staré vnútorne pole obsahovalo n prvkov tak táto operácia pridania jedného prvku
trvá n časových jednotiek.


Preto je vhodné už pri vytváraní zoznamu nastaviť s akým približným maximálnym počtom prvkov rátate. Viď príklad.


Príklad 6.2

using System;
using System.Collections.Generic;
//----------------------------------------------------

class MainClass
{

public static void Main(string[] args)
{

List<string> samoNastavene = new List<string>();
// Ako ziskat aktualnu maximalnu kapacitu
int kap = samoNastavene.Capacity;
Console.WriteLine("Trieda List po inicializacii ma kapacitu {0}",
kap);

Console.WriteLine("Pridame jeden prvok");
samoNastavene.Add("Ahoj");

kap = samoNastavene.Capacity;
Console.WriteLine("Trieda List zvysila kapacitu na {0}",
kap);

// Vytvorime zoznam s vlastnou
// pociatocnou kapacitou 10 prvkov

Console.WriteLine("Vytvorime prazdny zoznam " +
"na zaciatok pre 10 prvkov");
List<int> rucneNastavene = new List<int>(10); //!!!!!
for(int i = 0; i < 10; i++)
rucneNastavene.Add(i);

kap = rucneNastavene.Capacity;
Console.WriteLine("Pridali sme 10 prvkov a kapacita je {0}",
kap);

Console.WriteLine("Pridame jeden prvok");
rucneNastavene.Add(55);

kap = rucneNastavene.Capacity;
Console.WriteLine("A kapacita sa zvysila na {0}",kap);
Console.ReadLine();
}

}

//----------------------------------------------------
Príklad na stiahnutie





V príklade vidíte, že ak chceme zoznam pripraviť na predpokladaná maximálnu veľkosť 10 prvkov, musíme tak urobiť v konštruktore.
Potom ak prekročíme rozsah tak sa nič zlé nestane, jednoducho pole zväčší svoju dĺžku na dvojnásobok pôvodnej a pridá nový prvok.


POZOR! Nezamieňajte si vlastnosť Capacity Count!!!
Count je počet uložených prvkov.
Capacity – koľko maximálne prvkov môže byť uložených v zozname kým nenastane rozširovanie poľa.


>>Vyhľadávanie v zozname


Príklad 6.3
using System;
using System.Collections.Generic;
//----------------------------------------------------

class MainClass
{

public static void Main(string[] args)
{

List<int> vysky = new List<int>(4);
vysky.Add(150);

vysky.Add(202);

vysky.Add(185);

vysky.Add(192);

int jednaNajdena = vysky.Find(HladajVysku); //!!!
Console.WriteLine("Prva vyska, ktora vyhovuje intervalu (150,200)");
Console.WriteLine("je {0}",jednaNajdena);
// Mozeme najst aj vsetky vyhovujuce vysky
// Vystupom je novy zoznam typu List
Console.WriteLine(" Vsetky vysky, ktore vyhovuju");
List<int> vsetky = vysky.FindAll(HladajVysku);
for(int i = 0; i < vsetky.Count; i++)
Console.WriteLine("{0}",vsetky[i]);


Console.ReadLine();

}

//---------------------------------------------------

// Napiseme vlastnu funkciu ako
// porovnavacie kriteriu a jej meno
// pouzijeme ako parameter pre .Find( );
private static bool HladajVysku(int vyska) //!!!
{

if (vyska > 150 && vyska < 200)
return true;

else
return false;

}

}

//----------------------------------------------------
Príklad na stiahnutie



Ak chceme vyhľadávať nejaký prvok, či množinu prvkov, musíme si napísať funkciu, ktorá vyhodnocuje naše kritérium. Vstupom môže byť iba jedna premenná a výstupom vždy bool premenná (true alebo false).


>>Aplikácia jednej operácie na všetky prvky zoznamu
Tu dám len jednoduchý príklad, pretože je to na spôsob predchádzajúceho problému, kde je potrebne si vytvoriť vlastne funkcie, ktoré sa potom aplikujú hromadne na všetky prvky.


Príklad 6.4
using System;
using System.Collections.Generic;
//---------------------------------------------------

class MainClass
{

public static void Main(string[] args)
{

List<string> pismena = new List<string>(4);
pismena.Add("za");

pismena.Add("as");

pismena.Add("de");

pismena.Add("tt");

//Aplikacia ForEach na vsetky prvky
Console.WriteLine("Vypis vsetkych prvkov vlastnou funkciou");
pismena.ForEach(VypisPrvok); //!!!!
Console.WriteLine();

bool result = pismena.TrueForAll(DvaZnaky); //!!!!
Console.WriteLine("Test ci vsetky prvky maju len dva znaky");
Console.WriteLine("skoncil s vysletkom : {0}",result);
// A nakoniec pole utriedime
// pouzije standartny operator porovnania
// ale mozeme si spravit aj vlastny

pismena.Sort();

Console.WriteLine("\nNa vsetky prvky aplikujeme triediaci                                algoritmus");
pismena.ForEach(VypisPrvok); //!!!!
Console.ReadLine();

}

//---------------------------------------------------

private static void VypisPrvok(string prvok)
{

Console.WriteLine(">> {0} <<",prvok);
}

//---------------------------------------------------

private static bool DvaZnaky(string prvok)
{

if (prvok.Length == 2 )
return true;
else
return false;
}

}

//---------------------------------------------------
Príklad na stiahnutie



>>Čo bude nabudúce?
Budeme pokračovať v podkapitole Generics ďalšími triedami.


Michal Čižmár
micitn@orangemail.sk

Neprehliadnite: