Maps With Int Keys: Array vs. Dictionary
Behind the scenes Array
holds its values in two ways: a densely-packed array at the beginning and a sparsely-packed map after that. This means it can be used as a map where the keys are indexes and not take up a huge amount of wasted space. Dictionary
can also have int
keys. Which is faster? Today we’ll find out!
This is a performance test to read and write to Array
and Dictionary
with int
keys:
package { import flash.display.*; import flash.utils.*; import flash.text.*; public class ArrayVsDictionary extends Sprite { private var __logger:TextField = new TextField(); private function row(...cols): void { __logger.appendText(cols.join(",")+"\n"); } public function ArrayVsDictionary() { stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; __logger.autoSize = TextFieldAutoSize.LEFT; addChild(__logger); init(); } private function init(): void { var beforeTime:int; var afterTime:int; var i:int; var REPS:int = 10000000; var array:Array = new Array(); var dictionary:Dictionary = new Dictionary(); var j:int; row("Class", "Time"); beforeTime = getTimer(); for (i = REPS-1; i >= 0; --i) { array[i] = i; } afterTime = getTimer(); row("Array (write)", (afterTime-beforeTime)); beforeTime = getTimer(); for (i = REPS-1; i >= 0; --i) { dictionary[i] = i; } afterTime = getTimer(); row("Dictionary (write)", (afterTime-beforeTime)); beforeTime = getTimer(); for (i = REPS-1; i >= 0; --i) { j = array[i]; } afterTime = getTimer(); row("Array (read)", (afterTime-beforeTime)); beforeTime = getTimer(); for (i = REPS-1; i >= 0; --i) { j = dictionary[i]; } afterTime = getTimer(); row("Dictionary (read)", (afterTime-beforeTime)); } } }
I ran this test app in the following environment:
- Flex SDK (MXMLC) 4.6.0.23201, compiling in release mode (no debugging or verbose stack traces)
- Release version of Flash Player 11.4.402.265
- 2.3 Ghz Intel Core i7
- Mac OS X 10.8.1
And here are the results I got:
Class | Time |
---|---|
Array (write) | 403 |
Dictionary (write) | 708 |
Array (read) | 97 |
Dictionary (read) | 305 |
Array
is the clear winner here: about 2x faster for writing and 3x faster for reading! This will get even better if you stick to the dense portion (generally the front) of the Array
, but even in a completely sparse way you’re still going to beat Dictionary
hands-down.
Spot a bug? Have a suggestion? Post a comment!
#1 by Joran on September 10th, 2012 ·
One thing that I’ve noticed using arrays like this was a really weird and annoying bug in flash that forced me to use a dictionary.
What happened was this: I had an array that I used as a map to set items in. Let’s start with this situation:
Then fore some reason, when I deleted the value for index 2 (to make it null) this happened:
Index 1 became undefined for no reason at all. Problem was that my for each loop broke because undefined is a value it iterates trough.
Come to think about it, I should have used if(value == undefined) instead of switching to a dictionary…
#2 by Pavel on September 10th, 2012 ·
@Joran
full example please?
*damn it, missed the “Reply”*
#3 by Pavel on September 10th, 2012 ·
@Joran
full example please?
#4 by skyboy on September 25th, 2012 ·
Though, Adobe’s Arrays are a bit stupid when migrating between sparse/dense. Once you pass a threshold to qualify the Array as sparse, it isn’t converted back to dense unless you set/reduce its length to 0 (special code handles this, resetting the entire object). Accidentally making an Array sparse permanently impacts performance of that Array.
#5 by jackson on September 25th, 2012 ·
Sounds disastrous. Any idea where the threshold is? Any tests to show the effect?
#6 by skyboy on September 25th, 2012 ·
The minimum sparse index is defined as 32. If there are 2^32 elements or more, any index is not an int, or less than half of the dense array is actually occupied, from the first non-undefined element to the last non-undefined element (starting index for the dense array portion can be higher than 0); nulls count, then it is converted to sparse.
One possible test would be to define an array of 1000 elements, set each to null, then starting at index 1 and going to index 600 use the delete statement on each element. Iterating over the array several times in each state should show the difference between sparse/dense.
http://hg.mozilla.org/tamarin-redux/file/3fc566f3a8b3/core/ArrayObject.cpp#l112
#7 by skyboy on September 25th, 2012 ·
Er. My bad, when less than 1/4th of the dense portion is occupied. Indexes from 1 to 800.