.NET - Kolekce a seznamy objektů
Co tento článek ukazuje
- Základní přehled jmenného prostoru
System.Collections
- Práce s polem (třída
Array
) - Kolekce
ArrayList
,Hashtable
aSortedList
Datové struktury které pro ukládání seznamu prvků, nebo jiné kolekce jsou potřeba ve (skoro) každé aplikaci. Prostředí .NET obsahuje kromě obvyklého pole (se kterým se ale pracuje v každém jazyce mírně odlišně) ještě několik dalších typů kolekcí. Tento tutoriál slouží jako přehled několika základních typů kolekcí a snaží se zodpovědět otázku, kdy je vhodné použít jaký typ kolekce.
Práce s polem
Základní datový typ pro ukládání seznamu objektů je pole.
Pole je narozdíl od ostatních obecných datových struktur typové
(takže do pole objektů typu MujObjekt
nelze vložit nic
jiného než MujObjekt
). Hlavním omezením pole je,
že jeho délka se určuje při vytvoření, takže pokud předem nevíte
kolik prvků v seznamu bude, je práce s polem nešikovná. Pracovat
s polem (v C#) pravděpodobně již umíte, ale pro zopakování pár základních
konstrukcí:
// Vytvoreni (prazdneho) pole int[] cisla1=new int[5]; // Inicializace pole cisel int[] cisla2=new int[] {1,2,3,4,5}´ů // Prochazeni prvku v poli foreach(int i in cisla2) Console.WriteLine("{0}\n",i);
To byl pouze krátký úvod, protože v .NET lze s poli dělat ještě další
zajímavé věci a to pomocí třídy Array
. Pole je možné setřídit
(a to i v případě, že v něm jsou uloženy nějaké vaše objekty) a v setřízeném
poli je možno hledat (pomocí algoritmu binárního vyhledávání, který dokáže
v setřízeném poli rychle vyhledávat prvek). K řazení nebo hledání v poli, které
obsahuje nějaké vaše prvky je potřeba, nějakým způsobem poli umožnit
porovnávat dva prvky. Existují dvě možnosti jak toto dosáhnout. První možností je
předat poli objekt implementující rozhraní IComparer
(obsahuje metodu,
která porovnává dva prvky) a druhou možností je implementovat v prvku rozhraní
IComparable
(umožňuje porovnat daný prvek s jiným).
// Pole z minuleho prikladu je serazene a int
// implmentuje IComparable, tedy muzeme hledat takto:
int pos=Array.BinarySearch(cisla,2);
Předchozí ukázka vrátí pozici 1, což je správně, protože v C# se k prvnímu
prvku v poli přistupuje přes index 0 (tedy cisla[0]
).
Nyní se podívejme na složitější příklad:
// V poli budeme ukladat tyto objekty class Zamestnanec { public string Jmeno; public int Plat; public Zamestnanec(string jmeno,int plat) { Jmen=jmeno; Plat=plat; } } // Objekt, ktery porovnava zamestnance podle platu public class PorovnatPodlePlatu : IComparer { // x<y - zaporne cislo; x=y - nula; x>y - kladne cislo public int Compare(object x, object y) { return ((Zamestnanec)x).Plat-((Zamestnanec)y).Plat; } }
Zamestnanec[] zam=new Zamestnanec[5];
zam[0]=new Zamestnanec("Martin",15);
zam[1]=new Zamestnanec("Libor",10);
zam[2]=new Zamestnanec("David",5);
zam[3]=new Zamestnanec("Jiri",20);
zam[4]=new Zamestnanec("Tomas",15);
// Setridit pole podle platu
Array.Sort(zam,new PorovnatPodlePlatu());
Další kolekce
ArrayList
ArrayList
je velmi užitečná kolekce, která je podobná poli,
ale je "nafukovací", tedy nepotřebuje při vytváření znát celkovou délku.
To je velmi vhodné při načítání dat, pokud předem neznáte počet prvků.
Vnitřně ArrayList
funguje tak, že si vytvoří pole nějaké délky
a s ním pracuje. Pokud je kapacita nedostačující, tak si vytvoří nové delší pole
a prvky do něj zkopíruje. V konstruktoru je možné předat výchozí kapacitu, takže
pokud víte, že budete vkládat řádově stovky prvků je velmi vhodné vytvořit
ArrayList
přibližně s touto kapacitou. Vzhledem k tomu, že
ArrayList
vnitřně pracuje s polem, není překvapující, že
existují metody ArrayList.Sort
a ArrayList.BinarySearch
(a další), které dělají přesně totéž co v případě pole. Další užitečnou
metodou je metoda ToArray
, pomocí které je možné z objektu
typu ArrayList
vytvořit obyčejné pole (metodě je potřeba předat jako
parametr typ položky v seznamu a vrátí pole těchto položek).
Vytvorit a naplnit seznam ArrayList list=new ArrayList(); list.Add(new Zamestnanec("Ondrej",10)); list.Add(new Zamestnanec("Jan",1)); Seradit a prevest na pole list.Sort(new PorovnatPodlePlatu()); Zamestnanec[] zam2= (Zamestnanec[])list.ToArray(typeof(Zamestnanec));
Hashtable
Další zajímavá kolekce je Hashtable
. Tato kolekce umožňuje
podle klíče ukládat objekty, ale nepamatuje si pořadí v jakém jsou vkládány
ani není možné ji třídit a není možné vložit dvakrát stejný objekt!
Umožňuje ale velmi rychlý (nejrychlejší možný) přístup
k prvkům podle klíče, takže pokud potřebujete například přistupovat k
zaměstnancům podle jejich jména je toto ideální datová struktura.
Hashtable
funguje ve zkratce tak, že objekty ukládá
do nějakého vnitřního pole a index v tomto poli vypočítá z klíče pomocí
hashovací funkce (GetHashCode
), kterou má každý objekt.
Při vkládání se objekt ukládá na takto spočítaný index a při hledání objektu
podle klíče se vypočte index v poli a pokud tam je objekt s příslušným
klíčem tak je vrácen. Toto samo o sobě nestačí, protože je možné že index
v poli se vypočte pro dva různé objekty stejný (ikdyž je to málo pravděpodobné).
V tomto případě se musí nějakým způsobem spočítat nový index v poli, dokud
se nenalezne prázdné místo.
// Ulozime k zamestnanci jeho plat Hashtable tab=new Hashtable(); tab.Add("Tomas",15); tab.Add("Jiri",20); tab.Add("David",5); // .. nyni lze podle jmena rychle zjistit plat int plat=(int)tab["Tomas"];
V tomto příkladě ukládáme k zaměstnanci přímo jeho plat, ale ve skutečné
aplikaci je výhodné ukládat do Hashtable
objekt, který obsahuje
kompletní informace o zaměstnanci (tedy objekt Zamestnanec
).
SortedList
Poslední datová struktura o které napíšu více se jmenuje SortedList
a jak již jméno napovídá jedná se o seřazený seznam prvků. Do seznamu je možné
jednak vkládat dvojice klíč-hodnota (řadí se podle klíče) a klíč musí být
jedinečný. Pokud chcete ukládat pouze seřazený seznam objektů můžete
objekty vkládat jako klíče a položku hodnota nechat prázdnou
(tedy vkládat null
). Vnitřně funguje SortedList
velmi podobně jako ArrayList
s jediným rozdílem a to, že
při vkládání prvku zařadí prvek na správné místo a ne na konec seznamu.
K prvkům uloženým v seznamu SortedList
lze přistupovat podle
klíče (sorted[klic]
) a nebo podle indexu
(sorted.GetByIndex(2)
). Dále lze přistupovat ke kolekci obsahující
vložené klíče (sorted.Keys
) a hodnoty (sorted.Values
).
// Seznam bude radit podle jmena SortedList sorted=new SortedList(new PorovnatPodleJmena()); // Vlozime zamestnance jako klice sorted.Add(new Zamestnanec("Martin",15),null); sorted.Add(new Zamestnanec("Libor",10),null); sorted.Add(new Zamestnanec("Jiri",20),null); // .. zamestnanci jsou automaticky razeni foreach(Zamestnanec zamestnanec in sorted.Keys) Console.WriteLine("{0} ({1})",zamestnanec.Jmeno,zamestnanec.Plat);
Další datové typy
Ve jmenném prostoru System.Collections
jsou ješě dvě další třídy, které
nejsou v tomto článku popsány. První z těchto tříd je zásobník (Stack
),
který umožňuje přidávat a odebírat prvky z vrcholu (tedy odebírají se naposledy
vložené prvky). Druhá datová struktura je fronta (Queue
), která umožňuje prvky
z jedné strany vkládat a z druhé odebírat.
Existuje ještě mnoho dalších datových struktur, které je občas potřeba použít. .NET Framework bohužel neobsahuje implementaci žádných obecných stromových struktur, ale na www.codeproject.com naleznete několik velmi zajímavých článků na toto téma, takže pokud se chcete dozvědět více prohlédněte si odkazy v následujícím odstavci.
Soubory na stažení a odkazy
- A Tree Collection [^] - CodeProject.Com
- Red-Black Trees in C# [^] - CodeProject.Com