Arrays: Chapter 5 - ActionScript 3.0 Cookbook
Pages: 1, 2, 3, 4

## Section 5.12: Randomizing the Elements of an Array

### Problem

You want to randomize the elements of an array.

### Solution

Use the `sort( )` method with a compare function that randomly returns a positive or negative number.

### Discussion

There are lots of scenarios in which you might plausibly want to randomize the elements of an array. For example, you may have a game in which you want to randomize the letters of a word. Since you already know how to split the letters into elements of an array using the `split( )` method, you may need to randomize those elements. Or perhaps you are making a card game where each element in the array is a card, and you want to shuffle the deck.

There is more than one way to accomplish the task. However, one of the simplest ways is to create a compare function that randomly returns a positive or negative number, and use it in the `sort( )` method. See Recipe 5.11 for more information on compare functions.

The following is probably the simplest possible compare function for the job:

```function randomSort(elementA:Object, elementB:Object):Number {
return Math.random( ) - .5
}```

Math.random( ) returns a number between 0.0 and 1.0. If you subtract 0.5 from that number, you'll get a random number between -0.5 and 0.5. Remember that in a compare function, returning a negative number means to order the first element first, and a positive number tells the `sort( )` method to put the second element first. Since the odds you'll return are 50/50, the resulting order of the array is completely random.

The following is an example of randomizing an array:

```var numbers:Array = new Array( );
for(var i:int=0;i<20;i++) {
numbers[i] = i;
}
numbers.sort(randomSort);
for(var i:int=0;i<numbers.length;i++) {
trace(numbers[i]);
}```

This creates an array of 20 sequential numbers, and then randomizes and displays them. You can verify that the order is now quite random.

## Section 5.13: Getting the Minimum or Maximum Element

### Problem

You want to retrieve the minimum or maximum element from an array of numbers.

### Solution

Sort the array numerically, and then retrieve the first or last element from the sorted array.

### Discussion

You can quickly retrieve the minimum or maximum value from an array by sorting it. The following example illustrates how to do just that:

```var scores:Array = [10, 4, 15, 8];
scores.sort(Array.NUMERIC);
trace("Minimum: " + scores[0]);
trace("Maximum: " + scores[scores.length - 1]);```

Of course, if the existing order of the array is important, you'll want to make a copy of the array before sorting it. See Recipe 5.8.

You can optionally use the `ArrayUtilities.min( )` and `ArrayUtilities.max( )` methods.

Recipe 5.8

## Section 5.14: Comparing Arrays

### Problem

You want to compare two arrays to see if they are equivalent.

### Solution

Loop through each element of both arrays and compare them.

### Discussion

Since arrays are reference datatypes, using an equality operator with two array variables only checks to see if they point to the same spot in memory. For example:

```var letters:Array = ["a", "b", "c", "d"];
var lettersPointer:Array = letters;
trace(letters == lettersPointer);  // Displays: true```

However, if two arrays are equivalent yet don't point to the same spot in memory, an equality operation returns `false`:

```var letters1:Array = ["a", "b", "c", "d"];
var letters2:Array = ["a", "b", "c", "d"];
trace(letters1 == letters2];  // Displays: false```

Instead, you can loop through each of the elements of the arrays and compare them:

```var equivalent:Boolean = true;
for(var i:int = 0; i < letters1.length; i++) {
if(letters1[i] != letters2[i]) {
equivalent = false;
break;
}
}
trace(equivalent);  // Displays: true```

Optionally, you can use the `ArrayUtilities.equals( )` method. This method requires two parameters: the references to the two arrays to compare. The method returns a Boolean value that indicates whether the arrays are equivalent or not:

```var letters1:Array = ["a", "b", "c", "d"];
var letters2:Array = ["a", "b", "c", "d"];
trace(ArrayUtilities.equals(letters1, letters2));
// Displays: true```

By default, the order of the elements has to match in the two arrays. If you don't care whether the order of the elements matches, you can specify a third parameter for the `equals( )` method; a Boolean value indicating whether or not the order should be disregarded:

```var letters1:Array = ["a", "b", "c", "d"];
var letters2:Array = ["b", "a", "d", "c"];
trace(ArrayUtilities.equals(letters1, letters2));
// Displays: false
trace(ArrayUtilities.equals(letters1, letters2, true));
// Displays: true```

The `equals( )` method is fairly simple. The code is explained in the comments in the following code block:

```public static function equals(arrayA:Array,
arrayB:Array,
bNotOrdered:Boolean):Boolean {

// If the two arrays don't have the same number of elements,
// they obviously are not equivalent.
if(arrayA.length != arrayB.length) {
return false;
}

// Create a copy of each so that anything done to the copies
// doesn't affect the originals.
var arrayACopy:Array = arrayA.concat( );
var arrayBCopy:Array = arrayB.concat( );

// If the order of the elements of the two arrays doesn't
// matter, sort the two copies so the order of the copies
// matches when comparing.
if(bNotOrdered) {
arrayACopy.sort( );
arrayBCopy.sort( );
}

// Loop through each element of the arrays, and compare them.
// If they don't match, delete the copies and return false.
for(var i:int = 0; i < arrayACopy.length; i++) {
if(arrayACopy[i] != arrayBCopy[i]) {
delete arrayACopy;
delete arrayBCopy;
return false;
}
}

// Otherwise the arrays are equivalent.
// So delete the copies and return true.
delete arrayACopy;
delete arrayBCopy;
return true;
}```

## Section 5.15: Creating an Associative Array

### Problem

You want to create an array that uses named elements instead of numbered indexes.

### Solution

Create an associative array.

### Discussion

When working with sets of data in which each element has a specific meaning or importance, a typical, number-indexed array doesn't always suffice.

For example, if you are working with a set of data such as the names of members of a committee, a number-indexed array is sufficient:

`var aMembers:Array = new Array("Franklin", "Gina", "Sindhu");`

However, if each member of the committee plays a special role, a standard array offers no way to indicate that. To address the issue, you can use an `associative array`. In some languages, this is called a `hash table`. In ActionScript, it is actually just an instance of the `Object` class. An associative array uses named elements rather than numeric indexes. The names used to refer to elements are often called `keys` or `properties`. The keys can give a meaningful context to the associated element value.

You can create an associative array in ActionScript by using `object literal notation` or adding elements to an object. Despite their name, you don't use the `Array` class to create associative arrays. The `Array` class provides methods and properties that work with number-indexed arrays only--and not with associative arrays. Associative arrays should be instances of the `Object` class. Technically, since the `Object` class is the base class for all ActionScript classes, all ActionScript objects can be used as associative arrays. However, unless you have some specific reason for using another class as an associative array, it is best to simply use the generic `Object` class.

One way you can create an associative array is by using object literal notation. With this technique, use curly braces (`{ }`) to enclose a comma-delimited list of keys and values, which are separated by a colon (`:`), as shown in the following example:

```var memebers:Object = {scribe: "Franklin",
chairperson: "Gina",
treasurer: "Sindhu"};```

You can also create an associative array using the following multiline technique with the `Object` constructor. Although the object literal notation is fine for creating small associative arrays in a single step, you should use the `Object` constructor technique for creating larger associative arrays. It improves readability and lets you add properties to an associative array by assigning the properties (keys) on subsequent lines. For example:

```var members:Object = new Object( );
members.scribe = "Franklin";
members.chairperson = "Gina";
members.treasurer = "Sindhu";```

Although using an `Object` constructor is more common, you can initialize the associative array object by using an empty object literal in place of the `Object` constructor:

`var members:Object = {};`

You can retrieve the values from an associative array in two ways. The first way is to access the elements using property notation (with the dot operator):

`trace(members.scribe); // Displays: Franklin`

The other option for retrieving values from an associative array is using array-access notation. To use array-access notation, reference the associative array followed by the array-access operator (`[ ]`). Within the array-access operator, you must use the `string` value of the name of the key you wish to access:

`trace(members["scribe"]); // Displays: Franklin`

Array-access notation is extremely useful in situations in which there are multiple keys with names in a sequence. This is because you can dynamically generate the key string value, whereas you cannot do this with property notation; for example:

```var members:Object = new Object();
members.councilperson1 = "Beatrice";
members.councilperson2 = "Danny";

for (var i:int = 1; i <= 3; i++) {
trace(members["councilperson" + i];
}```

Array access notation is most frequently used when looping through every element in an associative array, as shown in Recipe 5.16.

You can use either the property notation or array-access notation to read or write the values of an associative array:

```var members:Object = new Object( );
members["councilperson"] = "Ruthie";
trace(members.councilperson);         // Displays: Ruthie
members.councilperson = "Rebecca";
trace(members["councilperson"]);      // Displays: Rebecca```

Recipe 5.16 contains more details on accessing named elements of an associative array.

## Section 5.16: Reading Elements of an Associative Array

### Problem

You want to loop through the elements of an associative array.

### Solution

Use a `for . . . in` statement.

### Discussion

You iterate through the elements of integer-indexed arrays by using a `for` statement. However, named elements in associative arrays cannot be accessed by a numeric index, and the order of associative array elements is not guaranteed, regardless of the order in which the elements are added to the array. For that reason, there are also no methods to sort or reverse an associative array, or otherwise change its order.

Fortunately, you can loop through the enumerable elements of an associative array by using a `for . . . in` statement. This statement iterates through all the readable properties of the specified object. The syntax for a `for . . . in` statement is as follows:

```for (key in object) {
// Actions
}```

The `for . . . in` statement doesn't require an explicit update statement because the number of loop iterations is determined by the number of properties in the object being examined. Note that key is a variable name that will be used to store the property name during each iteration, not the name of a specific property or key. On the other hand, object is the specific object whose properties you want to read. For example:

```var members:Object = new Object( );
members.scribe = "Franklin";
members.chairperson = "Gina";
members.treasurer = "Sindhu";

// Use a for . . . in statement to loop through all elements.
for (var sRole:String in members) {
// Displays:
// treasurer: Sindhu
// chairperson: Gina
// scribe: Franklin
trace(sRole + ": " + members[sRole]);
}```

When you use a `for . . . in` statement, you must use array-access notation (square brackets) with the associative array. If you try to use property notation (with the dot operator) it won't work properly. This is because the value that is assigned to the key iterator variable is the string name of the key, not the key's identifier.

A `for . . . in` loop does not display all built-in properties of an object. For example, it displays custom properties added at runtime, but it does not enumerate methods of built-in objects, even though they are stored in object properties.