Jak zrobić tablicę asocjacyjną/hashowanie w JavaScript

Muszę przechowywać statystyki używając JavaScript w taki sposób, jak zrobiłbym to w C#:

Dictionary<string, int> statistics;

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

Czy istnieje Hashtable lub coś w rodzaju Dictionary<TKey, TValue> w JavaScript?
Jak Mogę przechowywać wartości w taki sposób?

Author: Davide Cannizzo, 2009-07-30

11 answers

Użyj obiektów JavaScript jako tablic asocjacyjnych .

Tablica asocjacyjna: w prostych słowach tablice asocjacyjne używają łańcuchów zamiast liczb całkowitych jako indeksu.

Utwórz obiekt za pomocą

var dictionary = {};

JavaScript pozwala na dodawanie właściwości do obiektów za pomocą następującej składni:

Object.yourProperty = value;

Alternatywną składnią dla tego samego jest:

Object["yourProperty"] = value;

Jeśli Możesz, Utwórz również mapy obiektów typu klucz do wartości za pomocą następujących składnia:

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

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

Można iterację poprzez tablicę asocjacyjną, używając for..in loop konstruuj następująco

for(var key in Object.keys(dict)){
  var value = dict[key];
  /* use key/value for intended purpose */
}
 575
Author: Alek Davis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-11 06:24:11
var associativeArray = {};
associativeArray["one"] = "First";
associativeArray["two"] = "Second";
associativeArray["three"] = "Third";

Jeśli pochodzisz z języka obiektowego, powinieneś sprawdzić Ten artykuł .

 434
Author: Dani Cricco,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-23 12:39:46

Wszystkie nowoczesne przeglądarki obsługują obiekt JavaScript Map. Jest kilka powodów, które sprawiają, że korzystanie z mapy jest lepsze niż obiekt:

  • obiekt ma prototyp, więc na mapie są domyślne klucze.
  • Klucze obiektu są ciągami znaków, gdzie mogą być dowolną wartością dla mapy.
  • możesz łatwo uzyskać Rozmiar mapy, podczas gdy musisz śledzić rozmiar obiektu.

Przykład:

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"

Jeśli chcesz klucze, które nie są odniesione z innych obiektów do śmieci, rozważ użycie WeakMap zamiast mapy.

 164
Author: Vitalii Fedorenko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-12 01:33:22

Jeśli nie masz konkretnego powodu, aby tego nie robić, po prostu użyj normalnego obiektu. Właściwości obiektu w JavaScript można odwoływać się do składni w stylu hashtable:

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

ZARÓWNO foo jak i bar elementy mogą być teraz określane jako:

hashtable['foo'];
hashtable['bar'];

// Or
hashtable.foo;
hashtable.bar;

Oczywiście oznacza to, że Twoje klucze muszą być sznurkami. Jeśli nie są ciągami, są one konwertowane wewnętrznie na ciągi, więc może nadal działać. Przebieg może się różnić.

 133
Author: roryf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-11 06:26:56

Ponieważ każdy obiekt w JavaScript zachowuje się jak - i jest ogólnie zaimplementowany jako-hashtable, po prostu się z tym Zgadzam...

var hashSweetHashTable = {};
 49
Author: Shog9,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-11 06:25:04

W C# kod wygląda następująco:

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

Lub

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

W JavaScript:

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

Obiekt słownika C# zawiera użyteczne metody, takie jak dictionary.ContainsKey()

W JavaScript możemy użyć hasOwnProperty Jak:

if (dictionary.hasOwnProperty("sample1"))
    console.log("sample1 key found and its value is"+ dictionary["sample1"]);
 22
Author: Raj,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-12 01:34:20

Jeśli chcesz, aby Twoje klucze były dowolnym obiektem, a nie tylko łańcuchami, możesz użyć my jshashtable.

 18
Author: Tim Down,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-11 06:28:01

Lata temu zaimplementowałem następującą tabelę hashtable, która miała pewne funkcje, których brakowało w klasie Map. Jednak tak już nie jest. Teraz możliwe jest iterację nad wpisami Mapy, uzyskanie tablicy jej kluczy lub wartości lub obu (operacje te są zaimplementowane kopiowanie do nowo przydzielonej tablicy, chociaż - to strata pamięci i jej złożoność czasowa zawsze będzie tak zła jak O(n)), usunąć określone elementy podane w ich kluczu i wyczyścić całą mapę. Dlatego, moja implementacja hashtable jest przydatna tylko dla celów kompatybilności, chociaż w tym przypadku lepiej byłoby napisać odpowiedni polyfill. Sugerowałbym każdemu, kto użyłby mojej implementacji hashtable, aby zmienić ją tak, aby stała się polyfillem dla klasy Map.

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

Dokumentacja klasy Hashtable

Metody:

  • get(key)
    Zwraca wartość powiązaną z podanym kluczem.
    parametry:
    key: klucz, z którego aby pobrać wartość.

  • put(key, value)
    Przypisuje podaną wartość do podanego klucza.
    parametry:
    key: Klucz, do którego przypisana jest wartość.
    value: wartość przypisana do klucza.

  • remove(key)
    Usuwa podany klucz wraz z powiązaną z nim wartością.
    parametry:
    key: Klucz do usunięcia.

  • clear()
    Czyści cały hashtable, usuwając wszystkie jego pozycji.

  • indexOfKey(key)
    Zwraca indeks podanego klucza, zgodnie z dodaną kolejnością wpisów.
    parametry:
    key: Klucz do uzyskania indeksu.

  • indexOfValue(value)
    Zwraca indeks podanej wartości, zgodnie z dodanymi wpisami kolejności.
    parametry:
    value: wartość, której chcemy uzyskać indeks.
    uwagi:
    Ta informacja jest pobierana za pomocą indexOf() metoda tablicy, więc obiekty są porównywane przez tożsamość.

  • entryAt(index)
    Zwraca obiekt o właściwościach key i value, reprezentujący wpis w podanym indeksie.
    parametry:
    index: indeks wpisu do pobrania.

  • containsKey(key)
    Zwraca, czy hashtable zawiera określony klucz.
    parametry: key: Klucz do szukania.

  • containsValue(value)
    Zwraca, czy hashtable zawiera podaną wartość.
    parametry:
    value: wartość, której należy szukać.

  • forEach(iterator)
    Iteruje wszystkie wpisy w hashtable, wywołując podany iterator.
    parametry:
    iterator: metoda z trzema parametrami, key, value i index, gdzie index reprezentuje indeks wpisu zgodnie z kolejnością, w jakiej został dodany.

Właściwości:

  • length ( tylko do odczytu)
    Pobiera liczbę wpisów w hashtable.

  • keys (tylko do odczytu )
    Dostaje tablicę wszystkich kluczy w hashtable.

  • values (tylko do odczytu )
    Pobiera tablicę wszystkich wartości w tabeli hashtable.

  • entries (tylko do odczytu )
    Pobiera tablicę wszystkich wpisów w tabeli hashtable. Są reprezentowane tak samo jak metoda entryAt() tak.

 8
Author: Davide Cannizzo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-20 13:16:10
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;
    }
}
 6
Author: Birey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-04 15:51:21

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) {

      // Override 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' ] ] ]
*/

// Override 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 THE HASH TABLE HAS NOW DOUBLED IN SIZE UPON REACHING 75% CAPACITY, i.e. 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
Author: Alex Hawkins,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-11 06:32:25

Możesz go utworzyć, używając następującego wzoru:

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
Author: Ali Ezzat Odeh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-12 23:10:33