Now that we know you can use int keys with Object, it’s time to test whether or not this is any faster than String keys. Today’s article does just that and also tests int and String keys with Dictionary.

First of all, Dictionary has a lot of the same strange behavior regarding keys that Object has. For example, dict[3] = 1 then dict["3"] = 2 results in 2 overriding 1 but the key remaining the int 3. But dict["03"] = 10 results in a String key "03" with the int value 10.

Now to test the performance of int keys against String keys. The following test app builds an Object and a Dictionary of various sizes—1 through 100,000 in 10x increments—and then reads each key-value pair via an Array of indices.

package
{
	import flash.display.*;
	import flash.utils.*;
	import flash.text.*;
 
	public class KeyTypes extends Sprite
	{
		private var logger:TextField = new TextField();
		private function row(...cols): void
		{
			logger.appendText(cols.join(",") + "\n");
		}
 
		public function KeyTypes()
		{
			stage.align = StageAlign.TOP_LEFT;
			stage.scaleMode = StageScaleMode.NO_SCALE;
 
			logger = new TextField();
			logger.autoSize = TextFieldAutoSize.LEFT;
			addChild(logger);
 
			init();
		}
 
		private function init(): void
		{
			var REPS:int = 1000000;
			var i:int;
			var str:String;
			var beforeTime:int;
			var afterTime:int;
			var objTime:int;
			var dictTime:int;
			var obj:Object;
			var dict:Dictionary;
			var indices:Array;
 
			row("Size", "Key Type", "Object Time", "Dictionary Time");
 
			for each (var size:int in [1, 10, 100, 1000, 10000, 100000])
			{
				indices = new Array(REPS);
				for (i = 0; i < REPS; ++i)
				{
					indices[i] = i % size;
				}
				obj = new Object();
				dict = new Dictionary();
				for (i = 0; i < size; ++i)
				{
					obj[i] = i;
					dict[i] = i;
				}
 
				beforeTime = getTimer();
				for (i = 0; i < REPS; ++i)
				{
					obj[indices[i]];
				}
				afterTime = getTimer();
				objTime = (afterTime - beforeTime) / (Number(REPS)/1000000);
 
				beforeTime = getTimer();
				for (i = 0; i < REPS; ++i)
				{
					dict[indices[i]];
				}
				afterTime = getTimer();
				dictTime = (afterTime - beforeTime) / (Number(REPS)/1000000);
 
				row(size, "Int", objTime, dictTime);
 
				indices = new Array(REPS);
				for (i = 0; i < REPS; ++i)
				{
					indices[i] = "" + (i%size);
				}
				obj = new Object();
				dict = new Dictionary();
				for (i = 0; i < size; ++i)
				{
					str = "" + i;
					dict[i] = i;
					dict[str] = i;
				}
 
				beforeTime = getTimer();
				for (i = 0; i < REPS; ++i)
				{
					obj[indices[i]];
				}
				afterTime = getTimer();
				objTime = (afterTime - beforeTime) / (Number(REPS)/1000000);
 
				beforeTime = getTimer();
				for (i = 0; i < REPS; ++i)
				{
					dict[indices[i]];
				}
				afterTime = getTimer();
				dictTime = (afterTime - beforeTime) / (Number(REPS)/1000000);
 
				row(size, "String", objTime, dictTime);
			}
		}
	}
}

I ran this test in the following environment:

  • Release version of Flash Player 12.0.0.70
  • 2.3 Ghz Intel Core i7-3615QM
  • Mac OS X 10.9.1
  • Google Chrome 33.0.1750.146
  • ASC 2.0.0 build 354071 (-debug=false -verbose-stacktraces=false -inline -optimize=true)

And here are the results I got:

Size Key Type Object Time Dictionary Time
1 Int 31 30
1 String 90 82
10 Int 30 30
10 String 98 86
100 Int 30 30
100 String 218 206
1000 Int 31 30
1000 String 155 135
10000 Int 31 30
10000 String 168 150
100000 Int 30 30
100000 String 222 203

Int Key Access Time Chart

String Key Access Time Chart

Performance of int keys clearly differs from String keys in two ways. In the test environment int keys take about 30 milliseconds regardless of the index being read or the size of the Object or Dictionary being read from. String, on the other hand, takes a minimum of about 82 milliseconds with a Dictionary of size 1, rises slightly until 10, jumps to 200 at 100, falls to 150 at 1000, then rises back to 200 by 100,000. So the performance is both slow and inconsistent across sizes. Object and Dictionary, however, mirror each other closely over the whole range of sizes. Dictionary is slightly faster at all times.

Clearly, Object and Dictionary are implemented with two very different strategies for keys. One is for Array-like access via int keys. The other is for map-like access via String keys. Given that the performance of int keys is so much better than String keys, automatically converting from String keys to int keys, as seen in the previous article, makes more sense. It’s an optimization that hopefully won’t cause any strange behavior in your program, but certainly could if you don’t understand the flowchart.

For now, the advice is the same as it’s always been: use int keys when you need a map that’s based on indices and String keys when you need a map that’s based on names. However, if your map’s data is sequential in nature you should probably be using a Vector or an Array.

Spot a bug? Have a question or suggestion? Post a comment!