首页 文章

如何在JavaScript中进行关联数组/散列

提问于
浏览
505

我需要使用JavaScript存储一些统计信息,就像我在C#中这样做:

Dictionary<string, int> statistics;

statistics["Foo"] = 10;
statistics["Goo"] = statistics["Goo"] + 1;
statistics.Add("Zoo", 1);

在JavaScript中是否有 HashtableDictionary<TKey, TValue> 之类的内容?
我怎么能以这种方式存储 Value ?

11 回答

  • 20

    使用JavaScript objects as associative arrays .

    关联数组:简单来说,关联数组使用字符串而不是整数作为索引 .

    用 . 创建一个对象

    var dictionary = {};
    

    Javascript允许您使用以下语法向对象添加属性:

    Object.yourProperty = value;
    

    另一种语法是:

    Object["yourProperty"] = value;
    

    如果还可以使用以下语法创建值对象映射的键

    var point = { x:3, y:2 };
    
    point["x"] // returns 3
    point.y // returns 2
    

    您可以使用for..in循环结构迭代关联数组,如下所示

    for(var key in Object.keys(dict)){
      var value = dict[key];
      /* use key/value for intended purpose */
    }
    
  • 420
    var associativeArray = {};
    associativeArray["one"] = "First";
    associativeArray["two"] = "Second";
    associativeArray["three"] = "Third";
    

    如果您来自面向对象语言,则应检查this article .

  • 113

    除非您有特殊原因,否则只需使用普通对象即可 . 可以使用散列表样式语法引用Javascript中的对象属性:

    var hashtable = {};
    hashtable.foo = "bar";
    hashtable['bar'] = "foo";
    

    现在可以将 foobar 元素引用为:

    hashtable['foo'];
    hashtable['bar'];
    // or
    hashtable.foo;
    hashtable.bar;
    

    当然这意味着你的密钥必须是字符串 . 如果它们不是字符串,它们会在内部转换为字符串,因此它仍然有效,YMMV .

  • 126

    所有现代浏览器都支持javascript Map对象 . 使用Map优于Object的原因有两个:

    一个对象有一个原型,因此 Map 中有默认键 . Object的键是字符串,它们可以是Map的任何值 . 您可以轻松获取 Map 的大小,同时必须跟踪对象的大小 .

    例:

    var myMap = new Map();
    
    var keyObj = {},
        keyFunc = function () {},
        keyString = "a string";
    
    myMap.set(keyString, "value associated with 'a string'");
    myMap.set(keyObj, "value associated with keyObj");
    myMap.set(keyFunc, "value associated with keyFunc");
    
    myMap.size; // 3
    
    myMap.get(keyString);    // "value associated with 'a string'"
    myMap.get(keyObj);       // "value associated with keyObj"
    myMap.get(keyFunc);      // "value associated with keyFunc"
    

    如果希望对未从其他对象引用的键进行垃圾回收,请考虑使用WeakMap而不是Map .

  • 2

    由于JS中的每个对象都表现得像 - 并且通常被实现为 - 一个哈希表,我只需要...

    var hashSweetHashTable = {};
    
  • 493

    所以在C#代码看起来像:

    Dictionary<string,int> dictionary = new Dictionary<string,int>();
    dictionary.add("sample1", 1);
    dictionary.add("sample2", 2);
    

    要么

    var dictionary = new Dictionary<string, int> {
        {"sample1", 1},
        {"sample2", 2}
    };
    

    在JavaScript中

    var dictionary = {
        "sample1": 1,
        "sample2": 2
    }
    

    C#dictionary对象包含有用的方法,如JavaScript中的 dictionary.ContainsKey() ,我们可以使用 hasOwnProperty 之类的

    if (dictionary.hasOwnProperty("sample1"))
        console.log("sample1 key found and its value is"+ dictionary["sample1"]);
    
  • 0

    如果你需要你的键是任何对象而不是字符串,那么你可以使用我的jshashtable .

  • 5
    function HashTable() {
        this.length = 0;
        this.items = new Array();
        for (var i = 0; i < arguments.length; i += 2) {
            if (typeof (arguments[i + 1]) != 'undefined') {
                this.items[arguments[i]] = arguments[i + 1];
                this.length++;
            }
        }
    
        this.removeItem = function (in_key) {
            var tmp_previous;
            if (typeof (this.items[in_key]) != 'undefined') {
                this.length--;
                var tmp_previous = this.items[in_key];
                delete this.items[in_key];
            }
    
            return tmp_previous;
        }
    
        this.getItem = function (in_key) {
            return this.items[in_key];
        }
    
        this.setItem = function (in_key, in_value) {
            var tmp_previous;
            if (typeof (in_value) != 'undefined') {
                if (typeof (this.items[in_key]) == 'undefined') {
                    this.length++;
                } else {
                    tmp_previous = this.items[in_key];
                }
    
                this.items[in_key] = in_value;
            }
    
            return tmp_previous;
        }
    
        this.hasItem = function (in_key) {
            return typeof (this.items[in_key]) != 'undefined';
        }
    
        this.clear = function () {
            for (var i in this.items) {
                delete this.items[i];
            }
    
            this.length = 0;
        }
    }
    
  • 49

    我创建它来实现一些问题,例如对象键映射,枚举能力(使用 forEach() 方法)和清除 .

    function Hashtable() {
        this._map = new Map();
        this._indexes = new Map();
        this._keys = [];
        this._values = [];
        this.put = function(key, value) {
            var newKey = !this.containsKey(key);
            this._map.set(key, value);
            if (newKey) {
                this._indexes.set(key, this.length);
                this._keys.push(key);
                this._values.push(value);
            }
        };
        this.remove = function(key) {
            if (!this.containsKey(key))
                return;
            this._map.delete(key);
            var index = this._indexes.get(key);
            this._indexes.delete(key);
            this._keys.splice(index, 1);
            this._values.splice(index, 1);
        };
        this.indexOfKey = function(key) {
            return this._indexes.get(key);
        };
        this.indexOfValue = function(value) {
            return this._values.indexOf(value) != -1;
        };
        this.get = function(key) {
            return this._map.get(key);
        };
        this.entryAt = function(index) {
            var item = {};
            Object.defineProperty(item, "key", {
                value: this.keys[index],
                writable: false
            });
            Object.defineProperty(item, "value", {
                value: this.values[index],
                writable: false
            });
            return item;
        };
        this.clear = function() {
            var length = this.length;
            for (var i = 0; i < length; i++) {
                var key = this.keys[i];
                this._map.delete(key);
                this._indexes.delete(key);
            }
            this._keys.splice(0, length);
        };
        this.containsKey = function(key) {
            return this._map.has(key);
        };
        this.containsValue = function(value) {
            return this._values.indexOf(value) != -1;
        };
        this.forEach = function(iterator) {
            for (var i = 0; i < this.length; i++)
                iterator(this.keys[i], this.values[i], i);
        };
        Object.defineProperty(this, "length", {
            get: function() {
                return this._keys.length;
            }
        });
        Object.defineProperty(this, "keys", {
            get: function() {
                return this._keys;
            }
        });
        Object.defineProperty(this, "values", {
            get: function() {
                return this._values;
            }
        });
        Object.defineProperty(this, "entries", {
            get: function() {
                var entries = new Array(this.length);
                for (var i = 0; i < entries.length; i++)
                    entries[i] = this.entryAt(i);
                return entries;
            }
        });
    }
    

    类Hashtable的文档

    方法:

    • get(key)
      返回与指定键关联的值 .
      Parameters:
      key :从中检索值的键 .

    • put(key, value)
      将指定的值与指定的键关联 .
      Parameters:
      key :关联值的关键字 .
      value :与密钥关联的值 .

    • remove(key)
      删除指定的键及其值 .
      Parameters:
      key :要删除的密钥 .

    • clear()
      清除所有哈希表,删除键和值 .

    • indexOfKey(key)
      根据添加顺序返回指定键的索引 .
      Parameters:
      key :获取索引的关键 .

    • indexOfValue(value)
      根据添加顺序返回指定值的索引 .
      Parameters:
      value :获取索引的值 .
      Notes:
      此信息由数组的 indexOf() 方法检索,因此它仅使用 toString() 方法比较对象 .

    • entryAt(index)
      返回具有两个属性的对象:key和value,表示指定索引处的条目 .
      Parameters:
      index :要获取的条目的索引 .

    • containsKey(key)
      返回哈希表是否包含指定的键 .
      Parameters:
      key :检查的关键 .

    • containsValue(value)
      返回哈希表是否包含指定的值 .
      Parameters:
      value :要检查的值 .

    • forEach(iterator)
      迭代指定的 iterator 中的所有条目 .
      Parameters:
      value :具有3个参数的方法: key ,_1044953_和 index ,其中 index 表示条目的索引 .

    属性:

    • length (只读)
      获取哈希表中条目的计数 .

    • keys (只读)
      获取哈希表中所有键的数组 .

    • values (只读)
      获取哈希表中所有值的数组 .

    • entries (只读)
      获取哈希表中所有条目的数组 . 它们以与方法 entryAt() 相同的形式表示 .

  • 4

    https://gist.github.com/alexhawkins/f6329420f40e5cafa0a4

    var HashTable = function() {
      this._storage = [];
      this._count = 0;
      this._limit = 8;
    }
    
    
    HashTable.prototype.insert = function(key, value) {
      //create an index for our storage location by passing it through our hashing function
      var index = this.hashFunc(key, this._limit);
      //retrieve the bucket at this particular index in our storage, if one exists
      //[[ [k,v], [k,v], [k,v] ] , [ [k,v], [k,v] ]  [ [k,v] ] ]
      var bucket = this._storage[index]
        //does a bucket exist or do we get undefined when trying to retrieve said index?
      if (!bucket) {
        //create the bucket
        var bucket = [];
        //insert the bucket into our hashTable
        this._storage[index] = bucket;
      }
    
      var override = false;
      //now iterate through our bucket to see if there are any conflicting
      //key value pairs within our bucket. If there are any, override them.
      for (var i = 0; i < bucket.length; i++) {
        var tuple = bucket[i];
        if (tuple[0] === key) {
          //overide value stored at this key
          tuple[1] = value;
          override = true;
        }
      }
    
      if (!override) {
        //create a new tuple in our bucket
        //note that this could either be the new empty bucket we created above
        //or a bucket with other tupules with keys that are different than 
        //the key of the tuple we are inserting. These tupules are in the same
        //bucket because their keys all equate to the same numeric index when
        //passing through our hash function.
        bucket.push([key, value]);
        this._count++
          //now that we've added our new key/val pair to our storage
          //let's check to see if we need to resize our storage
          if (this._count > this._limit * 0.75) {
            this.resize(this._limit * 2);
          }
      }
      return this;
    };
    
    
    HashTable.prototype.remove = function(key) {
      var index = this.hashFunc(key, this._limit);
      var bucket = this._storage[index];
      if (!bucket) {
        return null;
      }
      //iterate over the bucket
      for (var i = 0; i < bucket.length; i++) {
        var tuple = bucket[i];
        //check to see if key is inside bucket
        if (tuple[0] === key) {
          //if it is, get rid of this tuple
          bucket.splice(i, 1);
          this._count--;
          if (this._count < this._limit * 0.25) {
            this._resize(this._limit / 2);
          }
          return tuple[1];
        }
      }
    };
    
    
    
    HashTable.prototype.retrieve = function(key) {
      var index = this.hashFunc(key, this._limit);
      var bucket = this._storage[index];
    
      if (!bucket) {
        return null;
      }
    
      for (var i = 0; i < bucket.length; i++) {
        var tuple = bucket[i];
        if (tuple[0] === key) {
          return tuple[1];
        }
      }
    
      return null;
    };
    
    
    HashTable.prototype.hashFunc = function(str, max) {
      var hash = 0;
      for (var i = 0; i < str.length; i++) {
        var letter = str[i];
        hash = (hash << 5) + letter.charCodeAt(0);
        hash = (hash & hash) % max;
      }
      return hash;
    };
    
    
    HashTable.prototype.resize = function(newLimit) {
      var oldStorage = this._storage;
    
      this._limit = newLimit;
      this._count = 0;
      this._storage = [];
    
      oldStorage.forEach(function(bucket) {
        if (!bucket) {
          return;
        }
        for (var i = 0; i < bucket.length; i++) {
          var tuple = bucket[i];
          this.insert(tuple[0], tuple[1]);
        }
      }.bind(this));
    };
    
    
    HashTable.prototype.retrieveAll = function() {
      console.log(this._storage);
      //console.log(this._limit);
    };
    
    /******************************TESTS*******************************/
    
    var hashT = new HashTable();
    
    hashT.insert('Alex Hawkins', '510-599-1930');
    //hashT.retrieve();
    //[ , , , [ [ 'Alex Hawkins', '510-599-1930' ] ] ]
    hashT.insert('Boo Radley', '520-589-1970');
    //hashT.retrieve();
    //[ , [ [ 'Boo Radley', '520-589-1970' ] ], , [ [ 'Alex Hawkins', '510-599-1930' ] ] ]
    hashT.insert('Vance Carter', '120-589-1970').insert('Rick Mires', '520-589-1970').insert('Tom Bradey', '520-589-1970').insert('Biff Tanin', '520-589-1970');
    //hashT.retrieveAll();
    /* 
    [ ,
      [ [ 'Boo Radley', '520-589-1970' ],
        [ 'Tom Bradey', '520-589-1970' ] ],
      ,
      [ [ 'Alex Hawkins', '510-599-1930' ],
        [ 'Rick Mires', '520-589-1970' ] ],
      ,
      ,
      [ [ 'Biff Tanin', '520-589-1970' ] ] ]
    */
    
    //overide example (Phone Number Change)
    //
    hashT.insert('Rick Mires', '650-589-1970').insert('Tom Bradey', '818-589-1970').insert('Biff Tanin', '987-589-1970');
    //hashT.retrieveAll();
    
    /* 
    [ ,
      [ [ 'Boo Radley', '520-589-1970' ],
        [ 'Tom Bradey', '818-589-1970' ] ],
      ,
      [ [ 'Alex Hawkins', '510-599-1930' ],
        [ 'Rick Mires', '650-589-1970' ] ],
      ,
      ,
      [ [ 'Biff Tanin', '987-589-1970' ] ] ]
    
    */
    
    hashT.remove('Rick Mires');
    hashT.remove('Tom Bradey');
    //hashT.retrieveAll();
    
    /* 
    [ ,
      [ [ 'Boo Radley', '520-589-1970' ] ],
      ,
      [ [ 'Alex Hawkins', '510-599-1930' ] ],
      ,
      ,
      [ [ 'Biff Tanin', '987-589-1970' ] ] ]
    
    
    */
    
    hashT.insert('Dick Mires', '650-589-1970').insert('Lam James', '818-589-1970').insert('Ricky Ticky Tavi', '987-589-1970');
    hashT.retrieveAll();
    
    
    /* NOTICE HOW HASH TABLE HAS NOW DOUBLED IN SIZE UPON REACHING 75% CAPACITY ie 6/8. It is now size 16.
     [,
      ,
      [ [ 'Vance Carter', '120-589-1970' ] ],
      [ [ 'Alex Hawkins', '510-599-1930' ],
        [ 'Dick Mires', '650-589-1970' ],
        [ 'Lam James', '818-589-1970' ] ],
      ,
      ,
      ,
      ,
      ,
      [ [ 'Boo Radley', '520-589-1970' ],
        [ 'Ricky Ticky Tavi', '987-589-1970' ] ],
      ,
      ,
      ,
      ,
      [ [ 'Biff Tanin', '987-589-1970' ] ] ]
    
    
    
    
    */
    console.log(hashT.retrieve('Lam James'));  //818-589-1970
    console.log(hashT.retrieve('Dick Mires')); //650-589-1970
    console.log(hashT.retrieve('Ricky Ticky Tavi')); //987-589-1970
    console.log(hashT.retrieve('Alex Hawkins')); //510-599-1930
    console.log(hashT.retrieve('Lebron James')); //null
    
  • 18

    您可以使用以下内容创建一个:

    var dictionary = { Name:"Some Programmer", Age:24, Job:"Writing Programs"  };
    
    //Iterate Over using keys
    for (var key in dictionary) {
      console.log("Key: " + key + " , " + "Value: "+ dictionary[key]);
    }
    
    //access a key using object notation:
    console.log("Her Name is: " + dictionary.Name)
    

相关问题