web-dev-qa-db-fra.com

Comment faire un tableau associatif / hachage en JavaScript

J'ai besoin de stocker des statistiques en JavaScript, comme si je le faisais en C #:

Dictionary<string, int> statistics;

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

Existe-t-il une Hashtable ou quelque chose comme Dictionary<TKey, TValue> en JavaScript?
Comment pourrais-je stocker des valeurs de cette manière?

539
George2

Utilisez objets JavaScript en tant que tableaux associatifs .

Tableau associatif: Dans les mots simples, les tableaux associatifs utilisent des chaînes au lieu de nombres entiers comme index.

Créer un objet avec

var dictionary = {};

Javascript vous permet d'ajouter des propriétés à des objets en utilisant la syntaxe suivante:

Object.yourProperty = value;

Une autre syntaxe pour la même chose est la suivante:

Object["yourProperty"] = value;

Si vous pouvez également créer une correspondance entre les objets et la valeur, avec la syntaxe suivante

var point = { x:3, y:2 };

point["x"] // returns 3
point.y // returns 2

Vous pouvez parcourir un tableau associatif en utilisant la construction de boucle for..in comme suit

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

Si vous venez d'un langage orienté objet, vous devriez vérifier cet article .

426
Dani Cricco

À moins que vous n'ayez une raison particulière de ne pas le faire, utilisez simplement un objet normal. Les propriétés d'objet en Javascript peuvent être référencées à l'aide de la syntaxe hashtable:

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

Les deux éléments foo et bar peuvent maintenant être référencés comme suit:

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

Bien sûr, cela signifie que vos clés doivent être des chaînes. S'ils ne sont pas des chaînes, ils sont convertis en interne en chaînes, de sorte que cela peut toujours fonctionner, YMMV.

130
roryf

Tous les navigateurs modernes prennent en charge un objet javascript Map . L’utilisation d’une carte est meilleure qu’un objet pour plusieurs raisons:

  • Un objet a un prototype, il y a donc des clés par défaut dans la carte.
  • Les clés d'un objet sont des chaînes, où elles peuvent être n'importe quelle valeur pour une carte.
  • Vous pouvez facilement obtenir la taille d'une carte tout en gardant une trace de la taille d'un objet.

Exemple:

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"

Si vous souhaitez que les clés qui ne sont pas référencées à partir d'autres objets soient collectées, utilisez un WeakMap au lieu d'une Map.

126

Étant donné que chaque objet de JS se comporte - et est généralement mis en œuvre comme - une table de hachage, je vais simplement avec cela ...

var hashSweetHashTable = {};
49
Shog9

donc en C # le code ressemble à:

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

ou

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

en JavaScript

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

L’objet dictionnaire C # contient des méthodes utiles comme dictionary.ContainsKey() en JavaScript, nous pourrions utiliser le hasOwnProperty comme

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

Si vous voulez que vos clés soient des objets plutôt que des chaînes, vous pouvez utiliser my jshashtable .

18
Tim Down

J'ai créé cela pour résoudre certains problèmes, tels que le mappage de clé d'objet, la possibilité d'énumération (avec la méthode forEach()) et l'effacement.

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;
        }
    });
}


Documentation de classe Hashtable

Les méthodes:

  • get(key)
    Renvoie la valeur associée à la clé spécifiée.
    Paramètres:
    key: La clé à partir de laquelle extraire la valeur.

  • put(key, value)
    Associe la valeur spécifiée à la clé spécifiée.
    Paramètres:
    key: La clé à laquelle associer la valeur.
    value: valeur à associer à la clé.

  • remove(key)
    Supprime la clé spécifiée avec sa valeur.
    Paramètres:
    key: La clé à supprimer.

  • clear()
    Efface toute la table de hachage, en supprimant les clés et les valeurs.

  • indexOfKey(key)
    Renvoie l'index de la clé spécifiée, en fonction de l'ordre d'ajout.
    Paramètres:
    key: La clé qui obtient l'index.

  • indexOfValue(value)
    Renvoie l'index de la valeur spécifiée, en fonction de l'ordre d'ajout.
    Paramètres:
    value: La valeur qui obtient l'index.
    Remarques:
    Cette information est extraite par la méthode indexOf() d'un tableau. Elle compare donc l'objet à la méthode toString().

  • entryAt(index)
    Renvoie un objet avec deux propriétés: clé et valeur, représentant l'entrée à l'index spécifié.
    Paramètres:
    index: L'index de l'entrée à obtenir.

  • containsKey(key)
    Indique si la table de hachage contient la clé spécifiée.
    Paramètres:
    key: La clé à vérifier.

  • containsValue(value)
    Indique si la table de hachage contient la valeur spécifiée.
    Paramètres:
    value: valeur à vérifier.

  • forEach(iterator)
    Itère toutes les entrées du iterator spécifié.
    Paramètres:
    value: Une méthode avec 3 paramètres: key, value et index, où index représente l'indice de l'entrée.

    Propriétés:

  • length (Lecture seule)
    Obtient le nombre d'entrées dans la table de hachage.

  • keys (Lecture seule)
    Obtient un tableau de toutes les clés de la table de hachage.

  • values (Lecture seule)
    Obtient un tableau de toutes les valeurs de la table de hachage.

  • entries (Lecture seule)
    Obtient un tableau de toutes les entrées de la table de hachage. Ils sont représentés sous la même forme que la méthode entryAt().

6
Davide Cannizzo
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;
    }
}
5
Birey

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
2
Alex Hawkins

Vous pouvez en créer un comme suit:

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)
1
Ali Ezzat Odeh