SORU
15 Aralık 2008, PAZARTESİ


JavaScript Hashmap Eşdeğer

Net this answer Bu gösterimde: update 3'te yapılmış gibi

var hash = {};
hash[X]

değil aslında karma nesne X; aslında sadece dönüştürür X bir dize () .toString() Eğer bir nesne ya da başka bir built-in dönüşüm için çeşitli ilkel türler) ve sonra görünen dize kadar, karma olmadan, "hash". Nesne eşitlik de işaretli değil - eğer iki farklı nesne aynı dize dönüşüm, sadece birbirimizin üzerine.

Bu göz önüne alındığında, orada javascript hashmaps herhangi bir etkin uygulamaları. (Örneğin, javascript hashmap 2. Google sonuç O(n) herhangi bir işlem için bir uygulama verir. Çeşitli diğer sonuçları eşdeğer dize temsilleri ile farklı nesnelerin birbirleri üzerine olduğu gerçeğini göz ardı.

CEVAP
20 Aralık 2008, CUMARTESİ


Sorun açıklaması

JavaScript yerleşik genel bulunmuyorgöstertürü (bazen denirilişkisel diziyasözlükisteğe bağlı ) tuşları ile rasgele değerler erişim sağlar. JavaScript temel veri yapısınesnesadece kabul eden harita özel bir tür anahtar olarak dizeleri ve prototip miras, alıcıları ve ayarlayıcıları ve biraz daha fazla voodoo gibi özel semantiği vardır.

Ne zaman usings nesneler olarak haritalar, hatırlaman gereken bu anahtarı olacaktır dönüştürülmüş bir dize değeri) toString(), hangi sonuçlar eşleme 5 '5' aynı değer ve tüm nesneleri yok üzerine yazma toString() yöntem için değer endeksli '[object Object]'. Ayrıca eğer hasOwnProperty() kontrol bile istemsiz kalıtsal özellikleri erişebilirsiniz.

JavaScript yerleşikdiziyazın bir bit yardımcı olmuyor: JavaScript diziler diziler, ama sadece biraz daha özel özellikleri ile nesneleri ilişkisel değildir. Eğer haritalar olarak kullanılan olamaz neden bilmek istiyorsanız, look here.

Eugene Çözüm

Eugene Lazutkin zaten sözlük bir nesnenin özellikleri olarak ilişkili değerleri aramak için kullanılan benzersiz bir dize oluşturmak için özel bir hash fonksiyonu kullanarak temel fikir nitelendirdi. Bu büyük olasılıkla nesneler şeklinde DAHİLİ olarak uygulanır, çünkü en hızlı çözüm olacaktırhash tabloları.

  • Not:Tablo (bazen denir . karma ^em>karma haritalar) göster karma kavramı sayısal değerler üzerinden destek dizi ve bir arama kullanarak belirli bir uygulama. Çalışma zamanı ortamı olabilir kullanın diğer yapılar gibiarama ağaçlarıyalisteler atlayınJavaScript nesneleri uygulamak için, ama nesneler temel veri yapısı olarak, yeterince optimize edilmiş olmalıdır.

Rasgele nesne için benzersiz bir karma değer elde etmek için, bir olasılık, küresel bir karşı kullanmak ve nesne karma değeri kendisi (bir özellik __hash adlı eg) önbellek.

Bu yaptığı hem de ilkel değerler ve nesneler için çalışan bir hash fonksiyonudur:

function hash(value) {
    return (typeof value)   ' '   (value instanceof Object ?
        (value.__hash || (value.__hash =   arguments.callee.current)) :
        value.toString());
}

hash.current = 0;

Bu işlev, Eugene tarafından açıklandığı gibi kullanılabilir. Kolaylık sağlamak için, daha fazla Map sınıf sarın edeceğiz.

* *Benim 20 uygulama

Aşağıdaki uygulama ayrıca her iki anahtar ve değerler üzerinde hızlı yineleme izin vermek için iki kat bağlantılı liste anahtar-değer çiftleri depolamak. Kendi denetim işlevini sağlamak, örnek oluşturma sonra 21* *yöntem üzerine yazabilirsiniz.

// linking the key-value-pairs is optional
// if no argument is provided, linkItems === undefined, i.e. !== false
// --> linking will be enabled
function Map(linkItems) {
    this.current = undefined;
    this.size = 0;

    if(linkItems === false)
        this.disableLinking();
}

Map.noop = function() {
    return this;
};

Map.illegal = function() {
    throw new Error("illegal operation for maps without linking");
};

// map initialisation from existing object
// doesn't add inherited properties if not explicitly instructed to:
// omitting foreignKeys means foreignKeys === undefined, i.e. == false
// --> inherited properties won't be added
Map.from = function(obj, foreignKeys) {
    var map = new Map;

    for(var prop in obj) {
        if(foreignKeys || obj.hasOwnProperty(prop))
            map.put(prop, obj[prop]);
    }

    return map;
};

Map.prototype.disableLinking = function() {
    this.link = Map.noop;
    this.unlink = Map.noop;
    this.disableLinking = Map.noop;
    this.next = Map.illegal;
    this.key = Map.illegal;
    this.value = Map.illegal;
    this.removeAll = Map.illegal;

    return this;
};

// overwrite in Map instance if necessary
Map.prototype.hash = function(value) {
    return (typeof value)   ' '   (value instanceof Object ?
        (value.__hash || (value.__hash =   arguments.callee.current)) :
        value.toString());
};

Map.prototype.hash.current = 0;

// --- mapping functions

Map.prototype.get = function(key) {
    var item = this[this.hash(key)];
    return item === undefined ? undefined : item.value;
};

Map.prototype.put = function(key, value) {
    var hash = this.hash(key);

    if(this[hash] === undefined) {
        var item = { key : key, value : value };
        this[hash] = item;

        this.link(item);
          this.size;
    }
    else this[hash].value = value;

    return this;
};

Map.prototype.remove = function(key) {
    var hash = this.hash(key);
    var item = this[hash];

    if(item !== undefined) {
        --this.size;
        this.unlink(item);

        delete this[hash];
    }

    return this;
};

// only works if linked
Map.prototype.removeAll = function() {
    while(this.size)
        this.remove(this.key());

    return this;
};

// --- linked list helper functions

Map.prototype.link = function(item) {
    if(this.size == 0) {
        item.prev = item;
        item.next = item;
        this.current = item;
    }
    else {
        item.prev = this.current.prev;
        item.prev.next = item;
        item.next = this.current;
        this.current.prev = item;
    }
};

Map.prototype.unlink = function(item) {
    if(this.size == 0)
        this.current = undefined;
    else {
        item.prev.next = item.next;
        item.next.prev = item.prev;
        if(item === this.current)
            this.current = item.next;
    }
};

// --- iterator functions - only work if map is linked

Map.prototype.next = function() {
    this.current = this.current.next;
};

Map.prototype.key = function() {
    return this.current.key;
};

Map.prototype.value = function() {
    return this.current.value;
};

Örnek

Aşağıdaki komut dosyası

var map = new Map;

map.put('spam', 'eggs').
    put('foo', 'bar').
    put('foo', 'baz').
    put({}, 'an object').
    put({}, 'another object').
    put(5, 'five').
    put(5, 'five again').
    put('5', 'another five');

for(var i = 0; i   < map.size; map.next())
    document.writeln(map.hash(map.key())   ' : '   map.value());

bu çıktıyı üretir:

string spam : eggs
string foo : baz
object 1 : an object
object 2 : another object
number 5 : five again
string 5 : another five

İleri değerlendirmeler

PEZ toString() yöntem üzerine, muhtemelen hash fonksiyonu ile önerdi. Bu temel öğeler için toString() değişen . ilkel değerler için işe yaramazsa, çünkü mümkün değildir ^em>çokkötü bir fikir). Eğer toString() keyfi nesneler için anlamlı bir değer döndürmek istiyorsak, bazı insanlar (ben dahil) düşünün Object.prototype, değiştirmek zorundayızyasak.

< / ^ hr .

Düzenleme:Map benim uygulama gibi diğer JavaScript güzellikler geçerli sürümü 33**.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Anthony Le

    Anthony Le

    10 EKİM 2006
  • jat4011

    jat4011

    16 EKİM 2010
  • monkophile

    monkophile

    25 Temmuz 2007