Arrays: Chapter 5 - ActionScript 3.0 Cookbook

by Joey Lott, Darron Schall, Keith Peters

This excerpt is from ActionScript 3.0 Cookbook. Well before Ajax and Windows Presentation Foundation, Macromedia Flash provided the first method for building "rich" web pages. Now, Adobe is making Flash a full-fledged development environment, and learning ActionScript 3.0 is key. That's a challenge for even the most experienced Flash developer. This Cookbook offers more than 300 solutions to solve a wide range of coding dilemmas, so you can learn to work with the new version right away.

buy button

Section 5.0: Introduction

Arrays are essential to successful ActionScript programming.

An array provides a way of grouping related data together, and then organizing and processing that data. The concept of an array should not be foreign to you. In fact, the concept is used all the time in everyday life. You can view a simple grocery list or to-do list as an array. Your address book is an array containing people's names, addresses, birthdates, and so on. Libraries keep track of books using an indexing system whereby each book becomes, conceptually, an element in a library's array.

In ActionScript, there are two kinds of arrays: integer-indexed and associative. Both array types group related data, but they use different means of accessing the data.

Integer-indexed array
Uses integers (numbers) as unique identifiers for each element in the array. Such arrays are ordered by index (i.e., element number), starting from 0. Each element occupies a numbered slot in the array. Integer-indexed arrays are ideal for sets of data that you want to work with in sequential order.
Associative array
Uses string keys to access each value. You can read more about associative arrays in Recipe 5.15.

Integer-indexed arrays are the focus of the majority of the recipes in this chapter, and unless otherwise specified, the term "array" refers to an integer-indexed array.

Of course, before you can use an array, you first need to know how to create one. There are two ways to construct a new array in ActionScript: with the constructor function or as an array literal. All arrays are members of the Array class. You can use the Array( ) constructor function to instantiate new array objects in one of three ways:

// Create an empty array.
var array:Array = new Array();

// Create an array with elements undefined elements.
var array:Array = new Array(elements); 

// Create an array with specified elements.
var array:Array = new Array(element0,...elementN);

The array literal notation also creates a new array, but without using the constructor function. Literal notation is convenient for specifying elements at the time of creation, such as:

var letters:Array = ["a", "b", "c"];

Some methods of the Array class modify the existing array on which the method is called, and others return a new array (offering an indirect way to create arrays).

You retrieve and set array elements using the array-access operator ( square brackets) and the index of the element you wish to get or set, for example:

// Set the fifth element of the array called items to "apples" 
// (array indexes start at 0).
items[4] = "apples";
     
// Display the fifth element in the Output window.
trace(items[4]);   // Displays: apples

ActionScript doesn't care what kind of values you store in an array. You can store strings, numbers, Booleans, or references to any kind of objects. And, unlike stricter programming languages, you can even store different datatypes in a single array. For example, this array stores a string, an integer, a Boolean, and an object:

var data:Array = ["a", 2, true, new Object()];

Unlike many languages, ActionScript doesn't force you to specify the number of elements in an array when it is declared.

Section 5.1: Adding Elements to the Start or End of an Array

Problem

You want to add elements to an existing array.

Solution

Use the push( ) method to append elements to the end of an array; use the unshift( ) method to insert elements at the beginning of an array.

Discussion

You append elements to the end of an existing array using the Array.push( ) method, passing it one or more values to be appended:

var array:Array = new Array();
array.push("val 1", "val 2");

You can also append a single element by using the array's length property as the index. Because ActionScript array indexes are zero-indexed (meaning that the first index is 0, not 1), the last element is at an index of Array .length - 1. Therefore, putting an element at index Array .length creates a new element right after the current last element; for example:

array[array.length] = "val 3";

If you set an element with an index that doesn't exist, the array extends itself to include the necessary number of elements automatically. If there are any intervening elements, they are initialized to undefined. For example, letters will contain the elements ["a", "b", "c", undefined, undefined, "f"] after you execute the following statements:

var letters:Array = ["a", "b", "c"];
letters[5] = "f";

Appending elements onto an array is common when you want to build an array incrementally or when you want to store the history of a user's actions for the purpose of implementing a back button or history feature.

To add elements to the beginning of an array, use the unshift( ) method. This shifts the existing elements up by one index position, and inserts the new element at index 0:

// Create an array with four elements:
// "a", "b", "c", and "d".
var letters:Array = new Array( );
letters.push("a", "b", "c", "d");
     
// Add "z" to the beginning of the array. This shifts all 
// the other elements so the value of "a" moves from 
// index 0 to index 1, etc.
letters.unshift("z");
     
// Display the results by looping through the elements. 
// See Recipe 5.2.
for (var i:int = 0; i < letters.length; i++) {
  trace(letters[i]);
}

Should you add elements to the beginning or the end of an array? That generally depends on how you intend to access or remove the elements at a later time. For example, if you want to access items in last in, first out (LIFO) order, you might use Array.push( ) to add elements to an array and Array.pop( ) to remove the elements in reverse order.

See Also

Recipe 5.2

Section 5.2: Looping Through an Array

Problem

You want to access each element of an array in sequential order.

Solution

Use a for loop that increments an index variable from 0 until it reaches Array. length. Use the index to access each element in turn.

Discussion

To access the values stored in the elements of an array, loop through the array's elements using a for loop. Because the first index of an array is 0, the index variable in the for statement should start at 0. The last index of an array is always 1 less than the length property of that array. Within the for statement, use the loop index variable within square brackets to access array elements. For example:

var letters:Array = ["a", "b", "c"];
for (var i:int = 0; i < letters.length; i++) {
  // Display the elements in the Output panel.
  trace("Element " + i + ": " + letters[i]);
}

The looping index variable (i in the example code) should range from 0 to one less than the value of the length property. Remember that the last index of an array is always one less than its length.

Alternatively, you can use a for statement that loops backward from Array. length -1 to 0, decrementing by one each time. Looping backward is useful when you want to find the last matching element rather than the first (see Recipe 5.3), for example:

var letters:Array = ["a", "b", "c"];
for (var i:int = letters.length - 1; i >= 0; i--){
  // Display the elements in reverse order.
  trace("Element " + i + ": " + letters[i]);
}

There are many instances when you might want to loop through all the elements of an array. For example, by looping through an array containing references to sprites, you can perform a particular action on each of the sprites:

for (var i:int = 0; i < sprites.length; i++){
  // Move each sprite one pixel to the right.
  sprites[i].x++;
}

You can store the array's length in a variable rather than computing it during each loop iteration. For example:

var length:int = sprites.length;
for (var i:int = 0; i < length; i++){
  // Move each sprite one pixel to the right.
  sprites[i].x++;
}

The effect is that there is a very marginal performance improvement because Flash doesn't have to calculate the length during each iteration. However, it assumes that you are not adding or removing elements during the loop. Adding or removing elements changes the length property. In such a case, it is better to calculate the length of the array with each iteration.

See Also

Recipe 12.8 for ways to loop through characters in a string. Recipe 5.16 for details on enumerating elements of an associative array. See also Recipe 5.3.

Section 5.3: Searching for Matching Elements in an Array

Problem

You want to find the first element in an array that matches a specified value.

Solution

Use a for statement to loop through an array and a break statement once a match has been found. Optionally, use the ArrayUtilities.findMatchIndex( ), ArrayUtilities.findLastMatchIndex( ), and/or ArrayUtilities.findMatchIndices( ) methods.

Discussion

When you search for the first element in an array that matches a specified value, you should use a for statement, as shown in Recipe 5.2, and add a break statement to exit the loop once the match has been found.

Using a break statement within a for statement causes the loop to exit once it is encountered. You should place the break statement within an if statement so it is executed only when a certain condition is met.

When searching for the first matching element, the importance of the break statement is twofold. First, you don't need to loop through the remaining elements of an array once the match has been found; that would waste processing time. In the following example, the break statement exits the loop after the second iteration, saving six more needless iterations. (Imagine the savings if there were a thousand more elements!)

Furthermore, the break statement is vital when searching for the first match because it ensures that only the first element is matched and that subsequent matches are ignored. If the break statement is omitted in the following example--all matching elements are displayed, as opposed to the first one only.

// Create an array with eight elements.
var letters:Array = ["a", "b", "c", "d", "a", "b", "c", "d"];
     
// Specify what we want to search for.
var match:String = "b";
     
// Use a for statement to loop through, potentially, 
// all the elements of the array.
for (var i:int = 0; i < letters.length; i++) {
     
    // Check whether the current element matches 
    // the search value.
    if (letters[i] == match) {
     
        // Do something with the matching element.
        // In this example, display a message 
        // for testing purposes.
        trace("Element with index " + i + 
              " found to match " + match);
     
        // Include a break statement to exit the for loop
        // once a match has been found.
        break;
    }  
}

You can also search for the last matching element of an array by reversing the order in which the for statement loops through the array. Initialize the index variable to Array .length -1 and loop until it reaches 0 by decrementing the index variable, as follows.

var letters:Array = ["a", "b", "c", "d", "a", "b", "c", "d"];
     
var match:String = "b";
     
// Loop backward through the array. In this example, 
// the "b" is at index 5.
for (var i:int = letters.length - 1; i >= 0; i--) {
    if (letters[i] == match) {
        trace("Element with index " + i + 
              " found to match " + match);
        break;
    }  
}

To simplify the process of searching for matching elements, you can use some of the static methods of the custom ArrayUtilities class. The class is in the ascb.util package, so the first step is to import the class:

import ascb.util.ArrayUtilities;

The ArrayUtilities class has three methods for finding matching elements-- findMatchIndex( ), findLastMatchIndex( ), and findMatchIndices( ). The findMatchIndex( ) method requires at least two parameters: a reference to the array you are searching, and the value you want to match. The method then returns either the index of the first matching element or -1 if no matches are found; for example:

var letters:Array = ["a", "b", "c", "d"];

trace(ArrayUtilities.findMatchIndex(letters, "b"));
// Displays: 1

trace(ArrayUtilities.findMatchIndex(letters, "r"));
// Displays: -1

You can also specify the starting index from which the search begins. That way, you can find matches subsequent to the first match. Specify the starting index as the third parameter; for example:

var letters:Array = ["a", "b", "c", "d", "a", "b", "c", "d"];

trace(ArrayUtilities.findMatchIndex(letters, "a", 1));
// Displays: 4

You can tell the method to find elements that are partial matches as well. By default, only exact matches are found. However, if you specify a value of true for the third parameter, the method finds any element containing the substring:

var words:Array = ["bicycle", "baseball", "mat", "board"];

trace(ArrayUtilities.findMatchIndex(words, "s", true));
// Displays: 1

If you want to run a partial match and still specify a starting index, simply pass the starting index as the fourth parameter.

The findLastMatchIndex( ) method works identically to findMatchIndex( ) except that it starts looking from the end of the array.

The findMatchIndices( ) method returns an array of indices for all elements that match the value passed in. The method requires at least two parameters--the array and the element you want to match. For example:

var letters:Array = ["a", "b", "c", "d", "a", "b", "c", "d"];

trace(ArrayUtilities.findMatchIndices(letters, "b"));
// Displays: 1,5

You can also run partial matches using findMatchIndices( ). Simply specify a Boolean value of true as the third parameter:

var words:Array = ["bicycle", "baseball", "mat", "board"];

trace(ArrayUtilities.findMatchIndices(words, "b", true));
// Displays: 0,1,3

Each of the ArrayUtilities methods described use the same basic techniques with a for statement. Let's take a look at the code for the methods. The findMatchIndex( ) method is fairly straightforward, and you can see the comments inline. One thing to note, however, is that the method doesn't use any break statements within the for loop. That's because it uses return statements if a match is found. In the context of a function or method, a return statement exits the for statement, so the break statement is not necessary:

public static function findMatchIndex(array:Array, element:Object):int {
    // Use a variable to determine the index 
    // from which to start. Use a default value of 0.
    var startingIndex:int = 0;

    // By default don't allow a partial match.
    var partialMatch:Boolean = false;

    // If the third parameter is a number, 
    // assign it to nStartingIndex.
    // Otherwise, if the fourth parameter is a number,
    // assign it to nStartingIndex instead.
    if(typeof arguments[2] == "number") {
        startingIndex = arguments[2];
    }    
    else if(typeof arguments[3] == "number") {
        startingIndex = arguments[3];
    }

    // If the third parameter is a Boolean value, 
    // assign it to partialMatch.
    if(typeof arguments[2] == "boolean") {
        partialMatch = arguments[2];
    }

    // Assume no match is found.
    var match:Boolean = false;

    // Loop through each of the elements of the array 
    // starting at the specified starting index.
    for(var i:int = startingIndex;
            i < array.length; i++) {

        // Check to see if the element either matches 
        // or partially matches.
        if(partialMatch) {
            match = (array[i].indexOf(element) != -1);
        }
        else {
            match = (array[i] == element);
        }

        // If the element matches, return the index.
        if(match) {
          return i;
        }
    }

    // The following return statement is only reached
    // if no match was found. In that case, return -1.
    return -1;
}

The findLastMatchIndex( ) method is almost identical to the findMatchIndex( ) method, except that it loops in reverse. The findMatchedIndices( ) method loops through the array to find every matching index. It appends each matching index to an array, and then it returns that array. It uses the findMatchIndex( ) method, as shown here:

public static function findMatchIndices(array:Array, 
element:Object, partialMatch:Boolean = false):Array {
    var indices:Array = new Array( );
    var index:int = findMatchIndex(array, 
                                   element,
                                   partialMatch);
    while(index != -1) {
        indices.push(index);
        index = findMatchIndex(array,
                               element,
                               partialMatch,
                               index + 1);
    }
    return indices;
}

See Also

Recipes 5.2 and 5.10

Pages: 1, 2, 3, 4

Next Pagearrow