Programowanie aplikacji RIA
Tablice w ActionScript cz. 2
W poprzednim wpisie o tablicach w ActionScript, pisałam o podstawach tworzenia i manipulowania tym typem danych. W tym poście przejdziemy do bardziej interesujących i zaawansowanych zagadnień dotyczących tablic.
Iteracja po elementach tabeli
Bardzo często używając tablic, musimy wykonać jakieś operacje na każdym jej elemencie. W ActionScript 3.0 są dwa sposoby na iterację po elementach tablicy.
Pętla for
Dobrze znana pętla w większości języków programowania. Jej użycie wygląda następująco:
var someArray = [1, 2, 3];
for(var i:int = 0; i < someArray.length; i++)
{
trace(someArray[i]);
}
metoda forEach()
Jest to nowa metoda obiektu Array (pojawiła się w wersji 3.0 ActionScript). Bardzo przydatna - powoduje wykonanie podanej funkcji na każdym elemencie tablicy. Zobaczmy jak jej używać:
var someArray = [1, 2, 3];
//funkcja wykonywana na każdym elemencie tablicy
function double(element:*, index:int, arr:Array):void
{
if(!isNaN(element))
{
trace(2*element);
}
}
someArray.forEach(double); //wyświetli 2 4 6
Jak widać funkcja przekazywana do metody forEach musi mieć trzy argumenty:
- element - parametr reprezentuje element tablicy, typ * oznacza dowolny typ
- index - to indeks aktualnie przetwarzanego elementu tablicy
- arr - tablica, na której elementach wykonujemy funkcję
Funkcja ta zwraca void.
Wykonanie operacji na wszystkich elementach tablicy
Metoda forEach nie jest jedynym dostępnym sposobem przeprowadzenia operacji na wszystkich elementach tablicy. ActionScript udostępnia jeszcze 3 ciekawe metody:
- every()
- some()
- filter()
Do wszystkich tych metod, jako argument, również musimy przekazać funkcję. Funkcja ta przyjmuje te same argumenty co funkcja przekazywana do metody forEach, z tą różnicą, że taka funkcja musi zwracać Boolean a nie void. Zatem ogólny zapis funkcji przekazywanej do tych 3 metod wygląda następująco:
function someFunction(element:*, index:int, arr:Array):Boolean
{
....
}
Te trzy metody powstały po to, by umożliwić sprawdzenie wszystkich elementów tablicy pod kątem określonego warunku.
Metoda every()
Metoda ta sprawdza warunek na każdym elemencie tablicy, aż do momentu, gdy któryś z nich zwróci false. Jeżeli tak się stanie, funkcja zatrzymuje się i zwraca false. Jeżeli żaden z elementów tablicy, po sprawdzeniu na nim warunku, nie zwróci false, wówczas metoda zwraca true. Zatem metoda ta jest przydatna, jeżeli chcesz sprawdzić warunek: "Czy każdy element spełnia mój warunek?".
Zobaczmy jak to działa w praktyce:
var arr:Array = [1,2,3,4,5];
//funkcja sprawdzająca czy element jest mniejszy od zera
function elementLessZero(element:*, index:int, arr:Array):Boolean
{
return element < 0;
}
//funkcja sprawdzająca czy element jest większy od zera
function elementMoreZero (element:*, index:int, arr:Array):Boolean
{
return element > 0;
}
//sprawdzamy
trace(arr.every(elementLessZero)); // wyświetli false
trace(arr.every(elementMoreZero)); //wyświetli true
Metoda some()
Metoda ta, sprawdza zdefiniowany warunek, na każdym elemencie tablicy, aż do momentu, gdy któryś z nich zwróci true. Jeżeli tak się stanie, metoda zatrzymuje się i zwraca true. Jeżeli żaden z elementów tablicy, po wykonaniu na nim warunku, nie zwróci true, wówczas cała metoda zwraca false. Zatem, jak łatwo się domyślić, za pomocą tej metody sprawdzamy warunek: "Czy którykolwiek z elementów tablicy spełnia mój warunek?"
var arr:Array = [1,2,3,4,5];
//funkcja sprawdzająca czy element jest mniejszy od zera
function elementLessTwo(element:*, index:int, arr:Array):Boolean
{
return element < 2;
}
//funkcja sprawdzająca czy element jest większy od zera
function elementMoreFive (element:*, index:int, arr:Array):Boolean
{
return element > 5;
}
//sprawdzamy
trace(arr.some(elementLessTwo)); // wyświetli true
trace(arr.some(elementMoreFive)); //wyświetli false
Metoda filter()
Jak sama nazwa wskazuje, ta funkcja służy do filtrowania elementów tablicy. Zwraca ona nową tablicę, złożoną z tych elementów, które spełniają zdefiniowany przez nas warunek. Przykład:
var arr:Array = [1,2,3,4,5];
//funkcja sprawdzająca czy element jest mniejszy od zera
function elementLessTwo(element:*, index:int, arr:Array):Boolean
{
return element < 2;
}
//filtrujemy
trace(arr.filter(elementLessTwo)); // wyświetli 1
Metoda map()
Czasami możesz potrzebować wykonać jakąś operację na każdym elemencie tablicy, ale bez zmiany pierwotnej tablicy. Przydatna okaże się wtedy metoda map.
var arr:Array = [1,2,3,4,5];
//funkcja zwiększa element o 2
function addTwo(element:*, index:int, arr:Array):Number
{
return element + 2;
}
var newArr:Array = arr.map(addTwo);
trace(arr); //wyświetli 1,2,3,4,5
trace(newArr); //wyświetli 3,4,5,6,7
Sprawdzanie, czy element znajduje się w tablicy
Jeżeli potrzebujesz sprawdzić, czy element istnieje w tablicy, posłuż się metodą indexOf. Metoda ta zwraca indeks szukanego elementu lub -1 jeżeli nie ma elementu w tablicy.
var arr:Array = ["jeden", "dwa", "trzy"];
if(arr.indexOf("jeden") != -1)
{
trace("indeks szukanego elementu: " + arr.indexOf("jeden")); //wyświetli 0
}
Sortowanie tablic
Używając tablic, najczęściej nie jest dla Ciebie istotna kolejność elementów. Czasem jednak musisz posortować tablicę. Możesz wówczas skorzystać z jednej z metod sortujących, udostępnianych w ActionScript.
metoda reverse()
Metoda ta po prostu odwraca kolejność elementów w tablicy.
var arr:Array = [1,2,3,4,5]; trace(arr.reverse()); //wyświetli 5,4,3,2,1
metoda sort()
To znacznie ciekawsza metoda, gdyż pozwala na sortowanie elementów w oparciu o przekazany algorytm. Jeżeli nie przekażemy do niej żadnego algorytmu, funkcja posortuje elementy alfabetycznie.
Algorytm sortowania określamy za pomocą funkcji, której ogólna definicja wygląda następująco:
function sortFunction(value1:*, value2:*):Number
Jak widać przyjmuje ona jako argumenty dwie wartości do porównania. W zależności od wyniku porównania zwracamy odpowiednią wartość numeryczną:
- jeżeli value1 ma się znaleźć przed value2, to zwracamy -1,
- jeżeli value1 jest równe value2, to zwracamy 0,
- jeżeli value1 ma się znaleźć po value2, to zwracamy 1
Przypuśćmy, że chcemy posortować tablicę zawierającą obiekty Battle. Obiekty reprezentują bitwy w historii Polski. Obiekt Battle został zdefiniowany następująco:
package pl.flexair
{
public class Battle
{
public var year:int;
public var place:String;
public function Battle(year:int, place:String)
{
this.year = year;
this.place = place;
}
public function toString():String
{
return "Rok " + this.year + ": " + this.place;
}
}
}
Zdefiniujmy sobie również tablicę historyBattle, która będzie przechowywała obiekty Battle:
var historyBattle:Array = [ new Battle(1621, "Chocim"), new Battle(1410, "Grunwald") ,new Battle(1610, "Kłuszyn")];
Następnie zdefiniujmy funkcję, która będzie sortować naszą tablicę po dacie bitwy i posortujmy naszą tablicę:
function sortByYear(battle1:Battle, battle2:Battle):Number
{
if(battle1.year == battle2.year)
{
return 0;
} else if (battle1.year < battle2.year)
{
return -1;
} else {
return 1;
}
}
trace(historyBattle.sort(sortByYear)); //wyświetli Rok 1410: Grunwald,Rok 1610: Kłuszyn,Rok 1621: Chocim
Teraz przypuśćmy, że w innym miejscu aplikacji potrzebujemy posortować elementy w tablicy, ale tym razem w odwrotnej kolejności. Czy musimy pisać kolejną funkcję sortującą? W takim przypadku wystarczy, że posłużymy się specjalną flagą, którą możemy przekazać jako kolejny parametr metody sort(). Flagi są to stałe statyczne, zdefiniowane w klasie Array. W naszym przypadku posłużymy się flagą Array.DESCENDING:
trace(historyBattle.sort(sortByYear, Array.DESCENDING)); //wyświetli Rok 1621: Chocim,Rok 1610: Kłuszyn,Rok 1410: Grunwald
Do metody sort można przekazywać więcej niż 1 flagę. Kolejne flagi łączymy za pomocą operatora bitowego "lub" (|), np.
trace(historyBattle.sort(sortByYear, Array.DESCENDING | Array.RETURNINDEXEDARRAY));
Oto jakie mamy flagi do dyspozycji w klasie Array:
- CASEINSENSITIVE - przy sortowaniu nie jest uwzględniana wielkość liter (domyślnie jest)
- DESCENDING - powoduje sortowanie elementów od najwyższej wartości do najmniejszej
- NUMERIC - jeżeli nie użyjesz tej flagi, przed sortowaniem wszystkie liczby są zamieniane na tekst. Użycie tej flagi zapobiega temu, więc sortujemy rzeczywiście liczby, a nie ich tekstowe odpowiedniki
- RETURNINDEXEDARRAY - powoduje, że w wyniku sortowania zwracana jest nowa tablica. Tablica, na której wykonujemy sortowanie pozostaje bez zmian
- UNIQUESORT - jej użycie powoduje zatrzymanie i zwrócenie przez funkcję sortującą 0, jeżeli znajdzie ona w tablicy dwa identyczne elementy
metoda sortOn()
Na koniec zostawiłam bardzo ciekawą metodę sortOn. Służy ona do sortowania po właściwościach obiektu. Jako argument przyjmuje ona tablicę z nazwami (nazwą) właściwości wg których chcemy posortować naszą tablicę z obiektami. Zatem powyższy przykład z tablicą historyBattle można by rozwiązać bez pisania własnego algorytmu sortowania, po prostu tak:
trace(historyBattle.sortOn(["year"]));
Sortowanie przy pomocy tej metody można również modyfikować za pomocą wcześniej wspomnianych flag.
| Drukuj artykuł | Ten wpis został napisany przez Olga Grabek na 25-07-2010 o 17:27, i jest w kategorii ActionScript. Podążaj za odpowiedziami do tego wpisu przez RSS 2.0. Możesz napisać komentarz, lub trackbacka z Twojej własnej strony. |
około 1 lat temu
Osobiście uważam, że operacje na tablicach to podstawowa umiejętność programowania w każdym języku. Także, duży, duży plus za te posty o metodach tablic w ActionScripcie
Napisz jeszcze jeśli możesz jak rozwiązujesz problem czyszczenia Tablic, usuwania jej elementów, usuwania całości tablicy. Bo ja czyszczę tablice w ten sposób:
while(Tablica){
Tablica.shift(); //lub pop();
}
Słyszałem także o takich metodach usuwania jak
Tablica.lenght = 0;
Tablica = new Array();
Tablica = [];
Natomiast metodą splice wycinam odpowiednie fragmenty tablicy – wcześniej wyszukane.
około 1 lat temu
Wszystko zależy od tego, co chcemy osiągnąć, np. ustawienie Tablica = []; zapewnia tylko czyszczenie instancji np.
var one:Array;
var two:Array;
one = two = ["a","b","c"];
one = [];
trace(two); // a,b,c
Twój sposób z wykorzystaniem metody shift() obchodzi ten problem.
Jeżeli chcemy całkowicie wyczyścić tablicę, można jeszcze skorzystać ze sposobu:
one.splice(0);
one = null;
Z tego co wyczytałam pozwala to na usunięcie obiektu przez garbage collector’a.