Pregunta

Necesito almacenar algunas estadísticas usando JavaScript de una manera como lo haría en C#:

Dictionary<string, int> statistics;

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

Hay un Hashtable o algo así Dictionary<TKey, TValue> en JavaScript?
¿Cómo podría almacenar valores de esa manera?

¿Fue útil?

Solución

Utilice objetos JavaScript como matrices asociativas .

  

Matriz asociativa: en palabras simples, las matrices asociativas usan cadenas en lugar de números enteros como índice.

Crear un objeto con

var dictionary = {};
  

Javascript le permite agregar propiedades a los objetos mediante la siguiente sintaxis:

Object.yourProperty = value;

Una sintaxis alternativa para el mismo es:

Object["yourProperty"] = value;

Si también puede crear claves para asignar mapas de objetos con la siguiente sintaxis

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

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

Puede iterar a través de una matriz asociativa utilizando la construcción del bucle for..in de la siguiente manera

for(var key in Object.keys(dict)){
  var value = dict[key];
  /* use key/value for intended purpose */
}

Otros consejos

var associativeArray = {};
associativeArray["one"] = "First";
associativeArray["two"] = "Second";
associativeArray["three"] = "Third";

Si viene de un lenguaje orientado a objetos, debe consultar este artículo .

A menos que tengas una razón específica para no hacerlo, simplemente usa un objeto normal.Se puede hacer referencia a las propiedades de los objetos en Javascript utilizando la sintaxis de estilo de tabla hash:

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

Ambos foo y bar Ahora se puede hacer referencia a los elementos como:

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

Por supuesto, esto significa que sus claves deben ser cadenas.Si no son cadenas, se convierten internamente en cadenas, por lo que aún puede funcionar, YMMV.

Todos los navegadores modernos admiten javascript. Mapa objeto.Hay un par de razones que hacen que usar un mapa sea mejor que un objeto:

  • Un Objeto tiene un prototipo, por lo que hay claves predeterminadas en el mapa.
  • Las claves de un Objeto son Cadenas, donde pueden ser cualquier valor para un Mapa.
  • Puede obtener el tamaño de un mapa fácilmente mientras debe realizar un seguimiento del tamaño de un objeto.

Ejemplo:

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 desea que las claves a las que no se hace referencia desde otros objetos se recopilen como basura, considere usar un Mapa débil en lugar de un mapa.

Dado que cada objeto en JS se comporta como, y generalmente se implementa como, una tabla hash, simplemente sigo con eso ...

var hashSweetHashTable = {};

así que en C # el código se ve así:

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

o

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

en JavaScript

var dictionary = {
    "sample1": 1,
    "sample2": 2
}
El objeto del diccionario

C # contiene métodos útiles como dictionary.ContainsKey() en JavaScript podríamos usar hasOwnProperty like

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

Si necesita que sus claves sean cualquier objeto en lugar de solo cadenas, puede usar mi jshashtable .

Creé esto para lograr algún problema, como el mapeo de claves de objetos, la capacidad de enumeración (con forEach() método) y limpieza.

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


documentacion de clase Hashtable

Métodos:

  • get(key)
    Devuelve el valor asociado a la clave especificada.
    Parámetros:
    key:La clave de la que se recupera el valor.

  • put(key, value)
    Asocia el valor especificado a la clave especificada.
    Parámetros:
    key:La clave a la que asociar el valor.
    value:El valor a asociar a la clave.

  • remove(key)
    Elimina la clave especificada con su valor.
    Parámetros:
    key:La clave para eliminar.

  • clear()
    Borra toda la tabla hash, eliminando tanto las claves como los valores.

  • indexOfKey(key)
    Devuelve el índice de la clave especificada, según el orden de adición.
    Parámetros:
    key:La clave de la cual obtiene el índice.

  • indexOfValue(value)
    Devuelve el índice del valor especificado, según el orden de adición.
    Parámetros:
    value:El valor del cual obtiene el índice.
    Notas:
    Esta información es recuperada por indexOf() método de una matriz, por lo que compara el objeto solo con toString() método.

  • entryAt(index)
    Devuelve un objeto con dos propiedades:clave y valor, que representan la entrada en el índice especificado.
    Parámetros:
    index:El índice de la entrada a obtener.

  • containsKey(key)
    Devuelve si la tabla hash contiene la clave especificada.
    Parámetros:
    key:La clave para comprobarlo.

  • containsValue(value)
    Devuelve si la tabla hash contiene el valor especificado.
    Parámetros:
    value:El valor a comprobar.

  • forEach(iterator)
    Itera todas las entradas en el especificado. iterator.
    Parámetros:
    value:Un método con 3 parámetros: key, value y index, dónde index representa el índice de la entrada.

    Propiedades:

  • length (Solo lectura)
    Obtiene el recuento de las entradas de la tabla hash.

  • keys (Solo lectura)
    Obtiene una matriz de todas las claves de la tabla hash.

  • values (Solo lectura)
    Obtiene una matriz de todos los valores de la tabla hash.

  • entries (Solo lectura)
    Obtiene una matriz de todas las entradas de la tabla hash.Están representados en la misma forma del método. entryAt().

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

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

Puede crear uno usando lo siguiente:

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)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top