30 November 2010
General experience with programming in ActionScript 3 is suggested.
Beginning
Arrays are a fundamentally important data structure for programming. At their most basic, arrays are containers for sets of objects. Arrays make it mush easier to maintain and modify related objects. This is particularly evident when you have several variables that share something in common. For example, if you have a list of contacts, you can place them in an array, which then acts much like an address book - one that you can very easily search through, or extract specific entries from to make modifications.
The following sections describe array programming in more detail.
The most common type of array is an indexed array. In this type, an index number is provided to any element that is added to the array. Arrays in ActionScript 3.0 are zero-based; the first element is assigned an index of 0, the second an index of 1, and so on. You can access individual elements in an indexed array by specifying the index inside a bracket operator ( [ ] ):
// Create a new array, adding three elements to it
var arr:Array = new Array("a", "b", "c");
trace(arr); // output: a,b,c
// Overwrite the third item (at index 2) with a new string
arr[2] = "aa";
// Set the third index to a new string
arr[3] = "bb";
trace(arr); // output: a,b,aa,cc
Arrays can also contain other arrays. These are called multidimensional arrays. Arrays can visually be conceived as a single row, with each element being a column in the row. If an array contains an array for each element, this creates a two-dimesional array, which is analogous to a grid with many rows and many columns. A bitmap image can be described as a two-dimensional array, where each element is a row that contains elements for each column. Each of these columns contain color information for each pixel:
// Create a new array
var arr:Array = new Array();
arr[0] = new Array("a", "b", "c");
arr[1] = new Array("d", "e", "f");
arr[2] = new Array("g", "h", "i");
trace(arr); // output: a,b,c,d,e,f,g,h,i
trace(arr[0]); // output: a,b,c
trace(arr[0][0]); // output: a
trace(arr[0][1]); // output: b
trace(arr[0][2]); // output: c
trace(arr[2][2]); // output: i
The final type of array is an associative array, which are also commonly called a hash or map. These arrays do not contain indexes, but instead reference elements by a key. In ActionScript 3.0, an associative array is functionally equivalent to an instance of the Object class. The key strings of an associative array are analogous to property names of an object. Therefore, you can create an associative array by using either Object or Array syntax:
// Create a new array
var indexedArray:Array = new Array();
// Assign index 0 to a new string
indexedArray[0] = "bob";
trace(indexedArray[0]); // output: bob
trace(indexedArray.length); // output: 1
// Create a new array
var associativeArr:Array = new Array();
// Assign a new string to key "name", making the array associative
associativeArr["name"] = "bob";
trace(associativeArr["name"]) // output: bob
trace(associativeArr.length); // output: 0 (length method unavailable to associative arrays)
var obj:Object = new Object();
obj.name = "bob";
trace(obj.name); // output: bob
Note that regardless of how you create an associative array, it is an unordered set of name value pairs, and as such, it does not have the same capabilities as that of an indexed array. Once an array is passed a key value pair, that array can no longer use the length() method to determine how many elements are contained within.
You can specify a new value to a particular index of an array by using the bracket operator, but you can also add or remove elements to the beginning or end of an array, using native methods of the Array class. To add an element to the end of an array, use the push() method. To add an element to the beginning of an array, use the unshift() method. Analogously, you can remove elements from either the beginning or end of an array, using the shift() and pop() methods, respectively. The following example shows the difference between these methods:
var arr:Array = new Array();
arr.push("green");
arr.push("blue");
arr.push("violet");
trace(arr); // output: green,blue,violet
arr.unshift("yellow");
arr.unshift("orange");
arr.unshift("red");
trace(arr); // output: red,orange,yellow,green,blue,violet
// Remove the last item from the array
var lastItem:String = arr.pop();
trace(lastItem); // output: violet
// Remove the first item from the array
var firstItem:String = arr.shift();
trace(firstItem); // output: red
trace(arr); // output: orange,yellow,green,blue
You can add or remove elements from the middle of an array by using the splice() method. In either case, the first parameter of the splice() method is the index to begin adding or removing.
// Create an array with two strings
var arr:Array = new Array("black", "white");
// Add two to the beginning
arr.splice(0, 0, "red", "orange", "yellow");
If you are adding elements, specify zero for the second parameter, followed by a commma-delimited list of elements to add:
// Add colors to the end
arr.splice(5, 0, "green", "blue", "violet");
If you are deleting elements, specify the number to be deleted as the second parameter:
// Remove two in the middle, starting at the third index
arr.splice(3,2);
You can create a new array out of an existing array using either the slice() or concat() methods. The slice() method returns an array that is a subset between two indices. The concat() method returns an array that is a merger of the arguments passed to it. The original array or arrays that are passed to either of these methods remain unchanged:
// Create a combined array without changing an initial array
var initialArray:Array = new Array("red", "orange", "yellow");
// Create an array that combines the initial array with three more strings
var combinedArray:Array = initialArray.concat("green", "blue", "violet");
// Create a subset of this array without changing the original
var slicedArray:Array = combinedArray.slice(3);
trace(initialArray); // output: red,orange,yellow
trace(combinedArray); // output: red,orange,yellow,green,blue,violet
trace(slicedArray); // output: green,blue,violet
The Array class contains methods that simplify common tasks such as finding an element or modifying all elements within the array. This section will cover some of these methods in detail.
Five methods of the Array class use callback functions: every(), some(), forEach(), map(), and filter(). These methods expect a function as a parameter. The specified function once for each element of the array. Every callback function specified for these methods should expect three parameters: the first is a reference to the element in the array, the second is the index of that element in the array, and the third is the array itself.
These callback functions can easily execute code based on each element in an array. For example, you can trace out each element in an array with customized formatting using the forEach() method:
var arr:Array = new Array( { country:"Cameroon", continent:"Africa" },
{ country:"Laos", continent:"Asia" },
{ country:"Uruguay", continent:"South America" },
{ country:"Romania", continent:"Europe" },
{ country:"Canada", continent:"North America" } );
arr.forEach(traceContinent);
function traceContinent(element:*, index:int, arr:Array):void {
trace(element.country + " is found in " + element.continent);
}
The map() method is similar to forEach(), but it returns a new array composed of elements that the callback function returns. This example creates a DataProvider instance that is used to populate a list with a formatted string from elements of another array (note that you will need the List component to be in the library of the FLA in order to compile):
import fl.controls.Button;
import fl.controls.DataGrid;
import fl.controls.List;
import fl.data.DataProvider;
var famousWorks:Array = new Array( { author:"Homer", work:"The Iliad" },
{ author:"Jules Verne", work:"Journey to the Center of the Earth" },
{ author:"James Joyce", work:"Ulysses" },
{ author:"John Steinbeck", work:"Grapes of Wrath" },
{ author:"Allen Ginsberg", work:"Howl" } );
// create grid to show initial array
var grid:DataGrid = new DataGrid();
grid.width = 350;
grid.height = 125;
grid.move(10, 10);
grid.dataProvider = new DataProvider(famousWorks);
addChild(grid);
// create list for formatted output
var list:List = new List();
list.width = 350;
list.move(10, 180);
list.rowCount = famousWorks.length;
addChild(list);
// create button to trigger the map method
var mapBtn:Button = new Button();
mapBtn.x = 80;
mapBtn.y = 10 + grid.height + 10;
mapBtn.width = 200;
mapBtn.label = "Format using Array.map()";
addChild(mapBtn);
mapBtn.addEventListener(MouseEvent.CLICK, onMapButtonClick);
function onMapButtonClick(evt:MouseEvent):void
{
// generate a formmatted list using the map() method
var formattedWorks:Array = famousWorks.map(formatFamousWork);
var dp:DataProvider = new DataProvider(formattedWorks);
list.dataProvider = dp;
}
function formatFamousWork(element:*, index:int, arr:Array):String {
return element.work + " (by " + element.author + ")";
}
This example is illustrated below:
To get the source files for this example, download ArrayMapMethod.zip at the top of this page. The Flash Professional CS5 version of the FLA file is called ArrayMapMethod_CS5.fla.
To create a subset of another array, you can use the filter() method. In a callback function to a filter() call, you must return true if the element should be in the new array or false if the element should be excluded. The following example generates an array of 100 random numbers from 0 to 100 and uses the filter() method to create a subset of all of the numbers that are larger than 90:
var arr:Array = new Array();
var totalElements:uint = 100;
for(var i:uint = 0; i<totalElements; i++) {
arr[i] = Math.round(Math.random()*100);
}
function isLargerThan90(element:*, index:int, arr:Array):Boolean {
return element > 90;
}
var highestNumbers:Array = arr.filter(isLargerThan90);
trace(highestNumbers);
The every() and some() methods also expect a Boolean value from their callback functions. The every() method executes the callback function for each element in the array until the callback function returns false. Likewise, the some() method executes the callback function for each element in the array until the callback function returns true. This beahvior can be useful to determine if the array meets a particular criteria. The following example determines if an array is composed entirely of strings:
var arr:Array = new Array();
var totalElements:uint = 1000;
for(var i:uint = 0; i<totalElements; i++) {
arr[i] = "name";
}
trace("Array is entirely composed of strings: " + arr.every(hasOnlyStrings));
function hasOnlyStrings(element:*, index:int, arr:Array):Boolean {
return element is String;
}
arr[42] = 81; // change one element to a number
trace("Array is entirely composed of strings: " + arr.every(hasOnlyStrings));
You can search for an element in an array using the indexOf() or lastIndexOf() methods. These methods use optimized search algorithms, and will typically perform better than custom search loops. The following example compares the performance of searching using the indexOf() methods versus searching by looping and searching by using the for each construct:
// assumes having two components on the screen:
// 1. A TextArea named outputTxt
// 2. A Button named startBtn
var loopCount:Number = Math.pow(10,6);
var loopingTally:uint = 0;
var forEachTally:uint = 0;
var indexOfTally:uint = 0;
var testsToMake:uint = 5;
// Create a large array composed entirely of zeroes
var a:Array = new Array();
for (var i:uint=0; i<loopCount; i++)
{
a[i] = 0;
}
// Start a timer that will start a new test every half-second, up to the total tests needed
var t:Timer = new Timer(500,testsToMake);
// Run the makeTest function every time the timer ticks
t.addEventListener(TimerEvent.TIMER,makeTest);
// When the timer has completed, run the showResults function
t.addEventListener(TimerEvent.TIMER_COMPLETE,showResults);
t.start();
function findByLooping(toSearchFor:Number):uint {
var start:int = getTimer();
for (i=0; i<loopCount; i++)
{
if(a[i] == toSearchFor) {
var end:int = getTimer();
var elapsed:int = end - start;
trace ("Found " + toSearchFor + " by looping at index: " + i + " time: " + String(elapsed));
break;
}
}
return elapsed;
}
function findByForEach(toSearchFor:Number):uint {
var start:int = getTimer();
for each(var entry:Number in a)
{
if(entry == toSearchFor) {
var end:int = getTimer();
var elapsed:int = end - start;
trace ("Found " + toSearchFor + " in for each loop at time: " + String(elapsed));
break;
}
}
return elapsed;
}
function findByIndexOf(toSearchFor:Number):uint {
var start:int = getTimer();
var foundIndex:int = a.indexOf(toSearchFor);
var end:int = getTimer();
var elapsed:int = end - start;
trace ("Found " + toSearchFor + " by indexOf() at index: " + foundIndex + " time: " + String(elapsed));
return elapsed;
}
function makeTest(e:TimerEvent):void {
// Get a random number
var randomNumber:Number = Math.random();
// Assign it to a random index in our dummy array
a[Math.floor(Math.random()*loopCount)] = randomNumber;
// Find it, timing various methods
loopingTally += findByLooping(randomNumber);
forEachTally += findByForEach(randomNumber);
indexOfTally += findByIndexOf(randomNumber);
}
function showResults(e:TimerEvent):void {
trace("== Average search time by looping: " + loopingTally/testsToMake);
trace("== Average search time by for each: " + forEachTally/testsToMake);
trace("== Average search time by indexOf: " + indexOfTally/testsToMake);
}
Here is some sample output from this application:
== Average search time by looping: 134.6
== Average search time by for each: 26
== Average search time by indexOf: 6.4
As you can see searching by using the indexOf() method is considerably faster than the other two approaches.
Click the Start button to run the tests in the example below:
To get the source files for this example, download ArraySearchMethods.zip at the top of this page. The Flash Professional CS5 version of the FLA file is called ArraySearchMethods_CS5.fla.
For more information on how to sort an array, see the Array class in the ActionScript 3.0 Reference for the Adobe Flash Platform, which contains detailed coverage of how to use the sort() and sortOn() methods. The PlayList example is described in the "Working with arrays" section of the ActionScript 3.0 Developer's Guide.