|
Kolekce
Ve Smalltalku jsou datové struktury implementovány pomocí kolekcí, což jsou v podstatě klasické seznamy s různými vlastnostmi, aby se daly využít jako fronty, pole, množiny, zásobníky apod.
Styl práce s kolekcemi se liší od tradičního způsobu např. C++, kde jsme odkázání pouze na indexování či operace specifické pro daný typ abstraktního datového typu (principielně trochu blíže práci s kolekcemi jsou iterátory v knihovně STL).
Smalltalk se snaží, aby se programátor musel co nejméně zabývat indexováním a mohl se soustředit na provádění samotného algoritmu nad jednotlivými prvky.
To si může dovolit díky tomu, že jako parametr se dá předávat blok kódu (toho se využívá i u mnoha dalších programových konstrukcí).
Postupně si rozebereme jak správně používat kolekce v nejčastějších případech a přitom si popíšeme její nejdůležitější zprávy.
Také se něco málo zmíním o hierarchii kolekcí.
Přístup k jednotlivým prvkům kolekce
at: anIndexOrKey
Způsob identifikace objektu v kolekci je závislý na typu kolekce. Kolekce může být "indexována" číslem, klíčem tvořenými jiným objektem a podobně.
kolekce at: 1
kolekce at: #klic
Práce s kolekcí jako celkem
operátor čárka (,) pro spojování kolekcí
Spojí dvě libovolné kolekce do jedné (někdy je důležité si dát pozor jestli je zaručeno zachování pořadí prvků jako například u spojování dvou množin apod.)
kolekce1, kolekce2
Iterace nad všemi prvky kolekce
do: oneParameterBlock
Nejjednošší a uniformní způsob jak postupně pro všechny prvky kolekce provést právě jednou nějakou akci, je použít zprávu do:. Co se bude s každým vybraným elementem provádět je zapsáno v bloku s jedním parametrem, který je předán jako parametr této zprávy.
kolekce do: [:elem | Transcript show: elem asString; cr.]
with:do:
Potřebujete-li kombinovat prvky 2 kolekcí a to v tom samém pořadí, tak lze s výhodou využít tuto velmi pohodlnou zprávu:
"součet dvou vektorů uložených jako čísla v kolekcích (s definovaným pořadím prvků)"
vectorResult := OrderedCollection new: vector1 size.
vector1 with: vector2 do: [:elem1 :elem2 | vectorResult addTail: (elem1 + elem2).].
inject:into:
Pokud je potřeba postupně vybírat prvky kolekce a počítat z nich nějakou finální/celkovou hodnotu a tato hodnota má vztah k předchozí hodnotě odvozené od již zpracované části kolekce.
Tato funkce je poměrně složitá na jednoduché vysvětlení, takže na úvod pouze řeknu, že se jedná o funkci typu SCAN známou z funkcionálních jazyků a nabídnu hned několik praktických příkladů, které snad využití této zprávy dostatečně osvětlí.
{ příklad v mutaci pascalu - pro lepší pochopení i pro Squeakery-začátečníky }
celkove := init_hodnota;
for i := 1 to count(kolekce) do
celkove := operace(kolekce[i], celkove);
"return celkove"
"to samé ve Squeaku"
kolekce inject: init_hodnota into: [:celkove :elem | elem operace: celkove].
"případně opačné pořadí tj. celkove operace: elem"
"pokud je operace komutativní, tak je to ale jedno jaké použijete pořadí"
"příklad vlastního převodu kolekce na řetězec"
kolekce inject: '' into: [:str :obj | str, obj asString].
"příklad nerekurzivní implementace funkce 10 factorial (není však asi efektivní)"
(1 to: 10) inject: 1 into: [:fact :n | fact * n].
"suma čísel v kolekci"
kolekce inject: 0 into: [:suma :cislo | suma + cislo].
"nalezení a vrácení maxima z čísel v kolekci (kolekce může obsahovat i nečísla)"
kolekce inject: -(Float infinity) into: [:maximum :num | num isNumber ifTrue: [maximum max: num.] ifFalse: [maximum]].
"suma prefixů seznamu čísel (tj. pro #(2 1 3 0 2) bude výsledek #(2 3 6 6 8)"
kolekce inject: (OrderedCollection new: kolekce size) into: [:res :cislo | res, (res last + cislo)].
"pro pripomenuti, operator carka spojuje (konkatenuje) kolekce"
TODO: hierarchie kolekcí a hlavně kdy je vhodné kterou použít (např. které umí bezproblémů růst, jak implementovat růst kolekce, která to nativně neumí (využití proudů dat) apod.)
TODO: odzkoušet funkčnost příkladů :-)))
Odkaz na tuto stránku
- Články, poslední úprava dne 17 Únor 2010 v 11:18:52 uživatelem localhost
|