Requirements                                                                       Required products                                                                                                                               
Prerequisite knowledge                                                        Flash Builder (Download trial)
You need to be familiar with ActionScript 3                         Adobe Animate CC    
 
User level
Beginning

In previous articles, you learned about the array data structure, which provides a mechanism to store and retrieve data in your application. While an array is a very useful data structure, it relies upon index-based access to your data. Often, your application will call for other methods of storing and accessing information.
 
This article introduces associative arrays. Associative arrays are often referred to as maps, and are another simple data structure, or way of storing data in a computer. They work by storing a given piece of information via a key or label. That key is then used for retrieving or altering the data later. Maps can grow or shrink in size over time as you add or remove elements. In ActionScript 3, maps can be created using either the Object class or the Dictionary class.

 

Creating maps based on Object

 

The first step in using a map, or an associative array, is to create one. When you want to create a new map based on Object , you must first instantiate Object :
 
var map:Object = new Object();

 

 

Object is considered a dynamic class. This means that, unlike the classes you have learned to create so far, not all of its properties are known at compile time, which allows properties to be added and removed at any time.

 

The code below instantiates an Object, adds a property called name1 to it at runtime, and traces  the name1 property. It then attempts to trace an as yet unknown name2 property.
 
var map:Object = new Object(); map.name1 = "Lee"; trace( map.name1 ); //Lee trace( map.name2 ); //undefined

 

Internally, the object is acting as a map and associating key-value pairs. Its internal structure would look like this:
 

Key

Value

name1

Lee

 
Note that there is one and only one value associated with each key. So, after the following code executes, the property name1 would only be associated with 1026.
 
var map:Object = new Object(); map.name1 = "Lee"; trace(map.name1); //Lee map.name1 = 1026; trace(map.name1); //1026

Key

Value

name1

1026

 

Array syntax

While any type of value may be stored inside of a map, the key is always a String. When the key is a simple string like name1 , you can use dot syntax as shown in the previous examples. However, if the key is a more complicated string containing spaces or other characters not allowed in an ActionScript 3 property names, you must use array syntax[] . The following two operations are identical:
 
map.name1 = 1026; map["name1"] = 1026;
 
With array syntax, you could have a key such as "password please":
 
map["password please"] = "Fireplace"; map.username = "MLY";

Key

Value

password please

Fireplace

username

MLY

If you do not use array syntax with a complicated string, attempting to compile this line in ActionScript 3 will yield an error:

 

map.password please = "Fireplace"; //Compilation Error

 

Literal syntax

Objects can also be created through a literal syntax:

 

var map:Object = {};
 
One advantage of this syntax is that you can provide key-value pairs as part of the object's construction in the following way:
 
var map:Object = {name1:"Alan", name2:"Lee"};

Key

Value

name1

Alan

name2

Lee


 

Deleting keys

 
Deleting a key from an Object is performed via the ActionScript 3 delete operator. The following code adds two properties to the map and then deletes one of them:
 
var map:Object = {name1:"Alan", name2:"Lee"}; delete map[ "name1" ];

Key

Value

name2

Lee

 

Key Existence

You can check if a given key exists in a map using a method of the Object class named hasOwnProperty() . As the following code demonstrates, hasOwnProperty() returns true if the key exists and false if it does not.
 
var map:Object = {name1:"Alan", name2:"Lee"}; map.hasOwnProperty("name1"); //true map.hasOwnProperty("name2"); //true map.hasOwnProperty("name3"); //false delete map["name1"]; map.hasOwnProperty("name1"); //false map.hasOwnProperty("name2"); //true map.hasOwnProperty("name3"); //false

 

Looping

 

 
There are two types of loops that work directly with maps in ActionScript 3: the for..in loop and the for each..in loop. Both provide ways to iterate over maps to find or enumerate keys and values.
 
for loops review
As you learned in ActionScript 3 fundamentals: Loops, a for loop follows a simple syntax that allows it to iterate over values.
 
for (var i:int=0; i<5; i++) { trace( i ); } //Output 0 1 2 3 4
 
In this example, i is the iterator variable and its value changes with each iteration of the for
loop. Just like the for loop iterates over a numeric value, for..in and for each..in loops can iterate over keys or values of an object.
 
for..in loops
The for..in loop iterates through the keys of a map. You can think of Flash Player making a list of all of the keys of the map. Much like the iterator variable i in the for loop above iterated over the values 0 through 4, the variable named key in the example below will iterate over the list of all of the keys of the map— name1 and name2 . Look at the output of the following code:
 
var map:Object = {name1:"Alan", name2:"Lee"}; for(var key:String in map) { trace(key); } //Output name2 name1
 
Since the variable key will iterate through all of the keys in the map, you can use this variable with array syntax to get both the keys and the values.
 
var map:Object = {name1:"Alan", name2:"Lee"}; for(var key:String in map) { trace( key + ":" + map[key] ); } //Output name2:Lee name1:Alan
 
In this example, key is used as part of the expression map[key] which retrieves the value associated with the key from the map.
 
for each..in loops
Where the for..in loop iterates over the keys, the for each..in loop iterates over the values of the map. In this case, you can think of Flash Player making a list of all of the values stored in the map. For this map, the values are Alan and Lee . Again, like the variable key in the above examples, the variable named value in the example below will iterate overthe list of all of the values of the map— Alan and Lee.
 
var map:Object = {name1:"Alan", name2:"Lee"}; for each(var value:* in map) { trace(value); } //Output Lee Alan
 
Note that in this case, the key is not retrieved and presented to you, but rather only the values of the map. The use of the * as a data type is a very useful technique in this case. Maps based on Object must use strings for their keys but can contain any type of data as a value. The * indicates that you don't know what type of data might be found in the map.
 
Also note that the order in which the output is returned is often the reverse of the order that you placed items into the map. You should not rely on the order of the items retrieved from a for..in or a for each..in loop.
 

 

Creating maps based on Dictionary

 

So far you have created maps based on the Object class; however, there is a second class in ActionScript 3 that can be used to create maps: Dictionary . In the example below, a Dictionary is created, a key-value pair is added via dot notation, a key-value pair is added via array syntax, a key is deleted and then a for..in loop is used to enumerate the keys. 
 
 
var map:Dictionary = new Dictionary(); map.name1 = "Alan"; map["name2"] = "Lee"; delete map.name2; for(var key:String in map) { trace(key); } //Output name1
 
As you can see, in most ways, Dictionary behaves exactly the same as Object . However, there are several differences to note. First, the abbreviated Object syntax {} cannot be used with dictionaries, so you must populate them via array syntax or dot notation. Second, dictionaries can use objects fortheir keys. Third, dictionaries have an optional constructor argument to use weak keys.

 

Object Keys
When using Object to create a map, all keys must be strings. If you pass something as a key to the map that is not a String, it will be converted to a String to make a valid key.
 

var map:Object = new Object();
var mySprite1:Sprite = new Sprite();
var mySprite2:Sprite = new Sprite();
map["name1"] = "One";
map[mySprite1] = "Two";
map[mySprite2] = "Three";

for(var key:* in map) {
trace(key + ": is String - " + (key is String) );
trace(key + ": is Sprite - " + (key is Sprite) );
}

//Output
[object Sprite]: is String - true
[object Sprite]: is Sprite - false
name1: is String - true
name1: is Sprite - false

Key

Value

name1

One

[object Sprite]

Two

 
In the code above, mySprite is a Sprite , not a string. So, it was converted to a string to become a valid key. Sprite is a type of Object . All types of Object have a toString() method which returns a string representation of the Object . That string representation is the word "object" followed by a space and the name of the type of object enclosed in square brackets [] . Therefore the string representation of each Sprite instance, regardless of the name of the reference variable it is assigned to, will always be [object Sprite] . This becomes very problematic when you have multiple items that evaluate to the same String. For example, look at the result of the code below:
 
var map:Dictionary = new Dictionary(); var mySprite1:Sprite = new Sprite(); var mySprite2:Sprite = new Sprite(); map["name1"] = "One"; map[mySprite1] = "Two"; map[mySprite2] = "Three"; for(var key:* in map) { trace(key + ": is String - " + (key is String) ); trace(key + ": is Sprite - " + (key is Sprite) ); } //Output name1: is String - true name1: is Sprite - false [object Sprite]: is String - false [object Sprite]: is Sprite - true [object Sprite]: is String - false [object Sprite]: is Sprite - true

Key

Value

name1

One

[object Sprite]

Three

 

Notice that there are only two items in the map in the preceding example. When mySprite1 and mySprite2 were both converted to a String, they produced the same key: [object Sprite] . Therefore, the second one overwrote the first rather than remaining an independent entry in the map. As you can see from the output, the key is no longer a Sprite , but has been converted to a string. There is no way to get the original Sprite from this string.
 
Conversely, Dictionaries allow you to use an Object as a key, so the same code using a Dictionary yields a different result:
 
var map:Dictionary = new Dictionary(); var mySprite:Sprite = new Sprite(); map[mySprite] = "I have a Sprite";

Key

Value

name1

One

mySprite1

Two

mySprite2

Three

 

Notice that there are now three distinct items in the map. Whenmy Sprite1 and mySprite2 were used as keys in the Dictionary , they remained Sprites, they were not converted to strings.
 
Weak Keys
Using objects as keys in a dictionary is a very useful technique, but it has implications for garbage collection. Basically, garbage collection destroys objects when they are no longer in use in your program. Using an object as a key in a dictionary means that object is in use. If you are unfamiliar with the concepts of garbage collection, you might want to read Garbage collection internals for Flash Player and Adobe AIR and learn about those before proceeding.
 
Looking at the following code:
 
var map:Dictionary = new Dictionary(); var mySprite:Sprite = new Sprite(); map[mySprite] = "I have a Sprite";

 

After this code executes, Flash Player memory will look something like this:
 
Figure 1. Both map and mySprite reference the same Sprite instance
 
There is a reference to the Sprite instance from both the dictionary ( map ) and the mySprite variable. If you set the mySprite reference to null:
 
mySprite = null;
 
Flash Player memory will look something like this:

 

Figure 2. Only map has a reference to the Sprite instance
 
Since the sprite instance was added as a key to the dictionary, the dictionary maintains a reference to it. Therefore, the sprite instance will stay in memory until it is removed from the dictionary or until the dictionary itself is destroyed.
 
Normally, this is a very good thing as you wouldn't want an object used as a key in your dictionary to randomly disappear. However, there are times that you might want to store things in a dictionary but only keep a tenuous grasp on them. You can accomplish this by setting the weakKeys constructor argument to true during the Dictionary instantiation.
 
var map:Dictionary = new Dictionary(true); var mySprite:Sprite = new Sprite(); map[mySprite] = "I have a Sprite";
 
After this code executes, Flash Player memory will look something like this:
 
Figure 3. map has a weak reference to the Sprite instance
 
In this case, the dictionary only has a weak reference to the Sprite instance. It is represented by the dashed line in the diagram. If mySprite is set to null:
 
mySprite = null;
 
Flash Player memory will look something like this:
 
Figure 4. The only reference to the Sprite instance is a weak one from map
 
The only reference left to the sprite instance is the weak one from map . The garbage collector ignores weak references when it attempts to determine if objects are still in use. If there is only a weak reference to an object, the garbage collector determines the object is no longer in use, and the object is collected. If you were to run a for..in loop after garbage collection occurred, you would see that the map in this example no longer has any entries.
 

Where to go from here

 

The Object and Dictionary classes allow you to create associative arrays, or maps, inside of ActionScript 3. Object is a lighter-weight version that only allows strings to be used for keys, whereas Dictionary allows objects to be used as keys. Further,  Dictionary allows the option to maintain weak references to those object keys. 
 
Collectively these two classes provide mechanisms beyond Array for storing and managing data. For additional information, please read Garbage collection internals for Flash Player and Adobe AIR and Vectors and ByteArray (coming soon).