15

http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/

The dictionary does what I need but I do need to care about performance. Does anybody know if the Dictionary is implemented as a hashtable?

Or more specifically, does it perform in O(1)?

Bart van Heukelom
  • 43,244
  • 59
  • 186
  • 301
  • have a look at this: http://code.google.com/p/ashashmap/ – George Profenza Mar 03 '10 at 13:33
  • 1
    @George Profenza: as nice as it is, it's a totall overkill. why reimplement something that already exists natively? – back2dos Mar 03 '10 at 17:20
  • @back2dos you are right. It depends on the situation though. I didn't suggest to use that, but to have a look. Since the ashashmap is supposed to work as the Java one, using it should be easy, so for a quick and dirty job, should be fine. For speed critical code and keeping control of what happens all over the code, understanding and using the Dictionary object is way forward. I added a comment, not an answer because it's an extra thing, not a real answer. Thanks for showing me where I am not clear. – George Profenza Mar 03 '10 at 19:24

3 Answers3

14

it acts as a hashmap. in fact, every ActionScript object that is an instance of a dynamic class, acts as hashmap. of course keys can always collide with properties. this behaviour comes from JavaScript. I consider it a design failure.

Array is different in that it will perform some tricks on integer keys, and Dictionary is different in that it doesn't convert keys to strings, but uses any object value as key. Please note that Number and Boolean are both converted to String.

now why whould you care how it is implemented? if it is well implemented, you probably don't wanna know. You can benchmark it. It has O(1) for all operations and is reasonably fast (inserting costs a about twice as much time as an empty method call, deleting costs less). Any alternative implementation will be slower.

here a simple benchmark (be sure to compile it for release and run it in the right player):

package  {
    import flash.display.Sprite;
    import flash.text.TextField;
    import flash.utils.*;
    public class Benchmark extends Sprite {

        public function Benchmark() {
            var txt:TextField = new TextField();
            this.addChild(txt);
            txt.text = "waiting ...";
            txt.width = 600;        
            const repeat:int = 20;
            const count:int = 100000;
            var d:Dictionary = new Dictionary();
            var j:int, i:int;
            var keys:Array = [];
            for (j = 0; j < repeat * count; j++) {
                keys[j] = { k:j };
            }
            setTimeout(function ():void {
                var idx:int = 0;
                var out:Array = [];
                for (j = 0; j < repeat; j++) {
                    var start:int = getTimer();
                    for (i = 0; i < count; i++) {
                        d[keys[idx++]] = i;
                    }
                    out.push(getTimer() - start);
                }
                txt.appendText("\n" + out);
                start = getTimer();
                for (var k:int = 0; k < i; k++) {
                    test();
                }
                txt.appendText("\ncall:"+(getTimer() - start));
                idx = 0;
                out = [];
                for (j = 0; j < repeat; j++) {
                    start = getTimer();
                    i = 0;
                    for (i = 0; i < count; i++) {
                        delete d[keys[idx++]];
                    }               
                    out.push(getTimer() - start);
                }
                txt.appendText("\n" + out);
            },3000);//wait for player to warm up a little
        }
        private function test():void {}
    }
}
Taryn
  • 242,637
  • 56
  • 362
  • 405
back2dos
  • 15,588
  • 34
  • 50
  • Thanks, very informative. I want to know because I would have to decide whether to use this or use another class which is a hashmap (if this were not). I could profile it yes, but knowing whether it's a hashmap is easier. – Bart van Heukelom Mar 03 '10 at 21:42
  • @Bart van Heukelom: I'm happy to have helped. Still by "implemented as a Hashmap" I suppose you mean "implemented as java.util.Hashmap". And the answer is, I don't know. Probably not. Java Hashmap is optimized to perform well on JVM. In flash player, this mechanizm is native and fully transparent. I wouldn't be surprised if implementation changed, or depended on platforms. The only thing one can say for certain is that it acts exactly as a hash table is commonly defined, with O(1) also for insert/delete. – back2dos Mar 04 '10 at 07:36
  • Sorry for the confusion, I meant as a hashtable in general – Bart van Heukelom Mar 04 '10 at 09:43
  • 1
    See konkere's answer below - it's not a hashmap since it doesn't use a hash. java.util.Hashmap *is* a hashmap. AS Object is not, and assuming it is can lead to some very hard-to-find bugs. – Phil May 06 '11 at 16:08
  • @Phil: Where did I say it is a hashmap or it uses a hash? You are the only one daring to make absolute statements about its implementation. – back2dos May 06 '11 at 20:56
  • This is actually not entirely true. Dictionary appears to have 3 internal maps of type `int`, `String`, and `Object`. For example, logical integers, whether they are passed as numbers or strings (1 or "1") resolve to the same key value of type `int`. Meanwhile, negative numbers like -1 and "-1" will once again resolve to the same key, but will have type "String". Interestingly, -1 and "-1." (negative one DOT) will not equate to the same key, since -1 becomes "-1" which does not equal the string "-1.". On the other hand 1.5 will become a string key equivalent to "1.5". Avoid numeric keys. – Triynko Jan 15 '14 at 20:02
4

Nope, it's not. java hashmaps are based on hash codes, while Dictionary is based on strict equality (===) of keys and therefore must not be used if you plan to put objects as keys.

java:

class MyStuff {
  public final int id;

  MyStuff(int i) {
    this.id = i;
  }
  public int hashCode() {
    return this.id;
  }
  public int equals(MyStuff o) {
    return (this.id - o.id);
  }
}

Map<MyStuff, Object> m1 = new HashMap<MyStuff, Object>();
m1.put(new MyStuff(1),  new Object());
assert(m1.get(new MyStuff(1)) != null); //true

as3:

class MyStuff {
  public var id:Number;

  public function MyStuff(i:Number):void {
    this.id = i;
  }
  //no notion of hashCode or equals in AS3 Object class,
  //so we can't really control how the Objects are compared.
}

var d:Dictionary = new Dictionary();
d[new MyStuff(1)] = {};
trace(d[new MyStuff(1)]); //outputs null

I'm looking into the right way of implementing hashing in AS3, but it does look very unpromising...

Yog Sothoth
  • 344
  • 1
  • 4
  • 18
  • Strict equality is fine for my purposes. I'm making games, where natural objects correspond 1:1 to instances, unlike in an ORM situation. I'm more concerned about the random access performance. – Bart van Heukelom Jun 07 '10 at 19:45
  • Assuming strict equality, the object's address in memory can serve as its hashcode just fine. AFAIK ActionScript code can't obtain that value, but the native Flash implementation would have no problem with it. – Brilliand Oct 14 '11 at 02:34
0

The adobe documentation on associate arrays seems to imply that dictionaries are hashmaps:

"You can use the Dictionary class to create an associative array that uses objects for keys rather than strings. Such arrays are sometimes called dictionaries, hashes, or maps."

http://livedocs.adobe.com/flex/3/html/help.html?content=10_Lists_of_data_4.html

justkevin
  • 3,089
  • 3
  • 28
  • 33