วิธีการเชื่อมโยงอาเรย์ / hashing ใน JavaScript


574

ฉันต้องการเก็บสถิติบางอย่างโดยใช้ JavaScript ในแบบที่ฉันต้องการใน C #:

Dictionary<string, int> statistics;

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

มีHashtableหรือสิ่งที่ชอบDictionary<TKey, TValue>ใน JavaScript?
ฉันจะเก็บค่าได้อย่างไร?


1
js ถูกพิมพ์อย่างหลวม ๆ ดังนั้นจึงไม่มีวิธีประกาศสตริงหรือ int คุณสามารถประกาศ var และกำหนดสตริงหรือ int ได้ : D
Gordon Gustafson

คุณอาจต้องการดู xDict jsfiddle.net/very/MuVwdมันเป็นพจนานุกรม String => สิ่งที่เขียนใน Javascript
Robert

บทความนี้มีคำอธิบายที่ยอดเยี่ยมเกี่ยวกับวิธีการใช้อาร์เรย์แบบเชื่อมโยงภายใต้การนำเสนอใน Javascript jayconrod.com/posts/52/a-tour-of-v8-object-representation
Shuklaswag

คำตอบที่ยอมรับถูกเขียนขึ้นในปี 2009 - รองรับเฉพาะคีย์สตริงเท่านั้น สำหรับคีย์ไม่ใช่สตริงใช้แผนที่หรือ WeakMap เช่นเดียวกับในคำตอบของ
ToolmakerSteve

คำตอบ:


564

ใช้วัตถุ JavaScript ที่เชื่อมโยงอาร์เรย์

Array Associative Array: ในคำง่าย ๆ อาเรย์เชื่อมโยงใช้ Strings แทนจำนวนเต็มเป็นดัชนี

สร้างวัตถุด้วย

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 loop build ดังนี้

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

36
โปรดทราบว่าวิธีการของผู้เขียนในการเริ่มต้น "อาร์เรย์ที่เชื่อมโยง" ที่มีการnew Array()ขมวดคิ้ว ในที่สุดบทความกล่าวถึงข้อเสียและแนะนำnew Object()หรือ{}เป็นทางเลือกที่ต้องการ แต่นั่นใกล้ถึงจุดสิ้นสุดแล้วและฉันกลัวว่าผู้อ่านส่วนใหญ่จะไม่ได้ไปไกลขนาดนั้น
Daniel Lubarov

23
ล้มเหลว. JavaScript ไม่รองรับการอ้างอิงวัตถุเป็นกุญแจในขณะที่พจนานุกรม Flash / AS3 ทำ ใน JavaScript var obj1 = {}; var obj2 = {}; var table= {}; table[obj1] = "A"; table[obj2] = "B"; alert(table[obj1]); //displays Bเนื่องจากไม่สามารถแยกความแตกต่างระหว่างคีย์ obj1 และ obj2; พวกเขาทั้งคู่ถูกแปลงเป็นสตริงและกลายเป็น "Object" ผลรวมล้มเหลวและทำให้การจัดลำดับอย่างปลอดภัยสำหรับประเภทที่มีการอ้างอิงและการอ้างอิงแบบวนซ้ำไม่สมบูรณ์หรือยากใน JavaScript ง่ายใน Flash / AS3
Triynko

วิธีเดียวใน JS ที่เราสามารถตรวจสอบได้โดยการตรวจสอบความเท่าเทียมกันหรือการกำหนดวิธีการเท่ากับโดยสิ่งนี้: Point.prototype.equals = function(obj) { return (obj instanceof Point) && (obj.x === this.x) && (obj.y === this.y); };
Nadeem

1
@Leo console.log ({A: 'B', C: 'D'} [foo]) ควรให้ A B.
ychaouche

2
@Leo ตัวอย่างดูเหมือนผิด for... inสำหรับพินัยกรรมห่วงพจนานุกรมกุญแจของตนเพื่อให้Object.keysดูเหมือนว่ามี malplaced Object.keysส่งกลับอาร์เรย์ของคีย์ของพจนานุกรมและfor... inสำหรับลูปอาร์เรย์กว่า ของ "กุญแจ" ซึ่งสำหรับอาร์เรย์เป็นดัชนีของมันไม่ค่าของมัน
JHH

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

ถ้าคุณมาจากภาษาเชิงวัตถุคุณควรตรวจสอบบทความนี้


38
คุณสามารถทำได้ในบรรทัดที่น้อยลง: var associativeArray = {"one": "First", "two": "second", "สาม": "Third"}; จากนั้น associativeArray ["หนึ่ง"] จะส่งกลับ "First" และ assocativeArray ["สี่"] ส่งคืน null
Tony Wickham

2
ขออภัย @JuusoOhtonen ฉันเขียนโพสต์เมื่อ 6 ปีที่แล้ว (มันเหลือเชื่อว่าเวลาผ่านไปอย่างรวดเร็ว) ฉันได้อัพเดทลิงค์แล้ว โปรดตรวจสอบและอย่าลังเลที่จะถามว่าคุณมีข้อสงสัยใด ๆ หรือ
เปล่า

145

เบราว์เซอร์ที่ทันสมัยทั้งหมดรองรับวัตถุแผนที่จาวาสคริปต์ มีสาเหตุสองประการที่ทำให้การใช้แผนที่ดีกว่าวัตถุ:

  • วัตถุมีต้นแบบดังนั้นจึงมีปุ่มเริ่มต้นในแผนที่
  • กุญแจของวัตถุคือ Strings ซึ่งสามารถเป็นค่าใด ๆ สำหรับแผนที่
  • คุณสามารถรับขนาดของแผนที่ได้อย่างง่ายดายในขณะที่คุณต้องติดตามขนาดของวัตถุ

ตัวอย่าง:

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แทนการใช้แผนที่


5
หวังว่าในอีกไม่กี่ปีข้างหน้านี้จะได้รับการโหวตมากที่สุดสำหรับคำตอบ
คาเมรอนลี

1
@CameronLee แน่นอนมันจะ
Loïc Faure-Lacroix

1
สิ่งนี้Mapมีประโยชน์มากเมื่อคีย์ของคุณเป็นวัตถุ แต่ควรเปรียบเทียบตามค่าไม่ใช่การอ้างอิง
Siyuan Ren

7
มากกว่าหนึ่งปีหลังจากคำตอบนี้ถูกเขียนขึ้นก็ยังไม่เป็นความจริงที่ว่า "เบราว์เซอร์ที่ทันสมัยทั้งหมดรองรับแผนที่" เฉพาะบนเดสก์ท็อปเท่านั้นที่คุณสามารถวางใจได้ในการสนับสนุนแผนที่ขั้นต่ำ ไม่ได้อยู่ในอุปกรณ์มือถือ เช่นเบราว์เซอร์ Android ไม่มีการสนับสนุนแผนที่เลย แม้กระทั่งบนเดสก์ท็อปการใช้งานบางอย่างไม่สมบูรณ์ ตัวอย่างเช่น IE11 ยังคงไม่สนับสนุนการแจกแจงผ่าน "สำหรับ ... ของ ... " ดังนั้นหากคุณต้องการความเข้ากันได้ของ IE คุณต้องใช้. disehusting.forEach kludge ที่น่าขยะแขยง นอกจากนี้ JSON.stringify () ใช้งานไม่ได้กับ Map ในเบราว์เซอร์ใด ๆ ที่ฉันได้ลอง initializers ไม่ทำงานใน IE หรือ Safari
เดฟเบอร์ตัน

3
มีการสนับสนุนเบราว์เซอร์ที่ดีเยี่ยม ตรวจสอบอีกครั้ง. ไม่ว่าในกรณีใด ๆ มันค่อนข้างง่ายในการโปลิฟิลดังนั้นการสนับสนุนเบราว์เซอร์ดั้งเดิมจึงไม่ใช่ปัญหา
แบรด

132

ถ้าคุณไม่มีเหตุผลที่เฉพาะเจาะจงให้ใช้แค่วัตถุธรรมดา คุณสมบัติของวัตถุใน Javascript สามารถอ้างอิงได้โดยใช้ไวยากรณ์สไตล์ hashtable:

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

ทั้งองค์ประกอบfooและbarตอนนี้สามารถอ้างอิงเป็น:

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

แน่นอนว่านี่หมายความว่ากุญแจของคุณต้องเป็นสายอักขระ หากพวกเขาไม่ใช่สตริงพวกเขาจะถูกแปลงภายในเป็นสตริงดังนั้นมันอาจยังคงใช้งานได้ YMMV


1
คีย์เป็นจำนวนเต็มทำให้ฉันไม่มีปัญหา stackoverflow.com/questions/2380019/…
Jonas Elfström

10
Jonas: โปรดจำไว้ว่าจำนวนเต็มของคุณถูกแปลงเป็นสตริงเมื่อมีการตั้งค่าคุณสมบัติ: var hash = {}; hash[1] = "foo"; alert(hash["1"]);แจ้งเตือน "foo"
Tim Down

17
เกิดอะไรขึ้นถ้าหนึ่งในกุญแจของคุณคือ " proto " หรือ " parent "
PleaseStand

5
โปรดทราบว่าไม่สามารถใช้วัตถุเป็นคีย์ใน JavaScript พวกมันทำได้ แต่พวกมันถูกแปลงเป็น String ของพวกมันดังนั้น Object ใด ๆ ก็จะจบลงด้วยคีย์เดียวกัน ดูคำแนะนำ jshashtable ของ @ TimDown ด้านล่าง
ericsoco

21
ตัวอย่างนี้ทำให้คุณสับสนเนื่องจากคุณใช้ foo และ bar เป็นทั้งคีย์และค่าในสองกรณี ชัดเจนมากขึ้นแสดงให้เห็นว่าvar dict = {}; dict.key1 = "val1"; dict["key2"] = "val2";องค์ประกอบ key1 Dict สามารถอ้างอิงเท่ากันทั้งสองข้างและdict["key1"] dict.key1
Jim

49

เนื่องจากวัตถุใน JS ทุกตัวมีลักษณะเหมือน - และถูกนำไปใช้โดยทั่วไป - เป็น hashtable ฉันแค่ไปกับสิ่งนั้น ...

var hashSweetHashTable = {};

26
ลงเนื่องจากไม่แสดงวิธีเข้าถึงค่าใน "hashtable" อย่างแท้จริง
IQAndreas

ฉันสาย 9 ปี (ฉันไม่รู้อะไรมากเกี่ยวกับการเขียนโปรแกรมปล่อยให้ไซต์นี้โดดเดี่ยวไปก่อน) แต่ ... จะเกิดอะไรขึ้นถ้าคุณพยายามจัดเก็บคะแนนไว้บนแผนที่และต้องดูว่ามีบางอย่างอยู่แล้ว ที่จุดบนแผนที่? ในกรณีนี้คุณจะใช้ HashTable ได้ดีที่สุดโดยดูจากพิกัด ( วัตถุไม่ใช่สตริง )
Mike Warren

@ MikeWarren if (hashSweetHashTable.foo)ควรป้อน if block ถ้าfooตั้งไว้
Koray Tugay

21

ดังนั้นใน 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.ContainsKey() ใน JavaScript เราสามารถใช้สิ่งที่hasOwnPropertyคล้ายกันได้

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

1
โหวตขึ้นสำหรับฉันโดยไม่ต้องเขียนคำตอบเกี่ยวกับhasOwnProperty
brichins

18

หากคุณต้องการให้คีย์ของคุณเป็นวัตถุใด ๆ แทนที่จะเป็นแค่สตริงคุณก็สามารถใช้jshashtableของฉันได้


3
ฉันใช้เวลากี่ชั่วโมงในการสะดุดความจริงที่ว่า Objects ไม่สามารถใช้เป็นกุญแจสำหรับ JS-style-Object-as-associative-arrays ก่อนที่ฉันจะพบสิ่งนี้ ขอบคุณทิม
ericsoco

1
พจนานุกรม Flash / AS3 พร้อมด้วยภาษาอื่น ๆ ส่วนใหญ่รองรับการอ้างอิงวัตถุเป็นกุญแจ JavaScript ยังไม่ได้นำมาใช้ แต่ฉันคิดว่ามันเป็นข้อมูลจำเพาะในอนาคตในฐานะคลาสแผนที่บางประเภท อีกครั้งกับ polyfills ในระหว่างนี้; มากสำหรับมาตรฐาน โอ้รอ ... ในที่สุดในปี 2558 แผนที่ก็มาถึงแล้ว: stackoverflow.com/a/30088129/88409และได้รับการสนับสนุนโดยเบราว์เซอร์ "ทันสมัย" lol: kangax.github.io/compat-table/es6/# แผนที่ (และไม่รองรับกันอย่างแพร่หลายจริงๆ) เพียงหนึ่งทศวรรษหลัง AS3
Triynko

ทิมบางทีคุณควรอัพเดต jshashtable เพื่อใช้ Map () ในกรณีที่มีให้ใช้
เดฟเบอร์ตัน

1
@DaveBurton: แผนดี ฉันจะทำทันทีที่ฉันมีเวลา
Tim Down

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

1
สำหรับผู้ที่ลงคะแนนเสียงในเรื่องนี้คุณสามารถแสดงความคิดเห็นได้ไหม คำตอบนี้ถูกโพสต์ในปี 2011 และไม่ได้อยู่ในวันที่ปัจจุบัน
Birey

2
ฉันไม่ลงคะแนน แต่ ... คุณไม่ควรใช้อาร์เรย์เป็นวัตถุ ไม่แน่ใจ 100% ว่านี่เป็นความตั้งใจของคุณหรือไม่ ใช้ slice ในอาร์เรย์ที่ไม่ลบเพื่อทำดัชนีใหม่ ลบก็โอเค แต่จะตั้งค่าเป็นไม่ได้กำหนด - ดีกว่าที่จะชัดเจน; ใช้ = ไม่ได้กำหนดบนวัตถุด้วย b / c เร็วกว่า (แต่มีหน่วยความจำมากกว่า) ในระยะสั้น: ใช้วัตถุเสมอ: {}ไม่ใช่อาเรย์: []หรือnew Array()ถ้าคุณตั้งใจจะมีคีย์สตริงมิฉะนั้นเอ็นจิ้น js มีปัญหา - มันจะเห็น 2 ประเภทสำหรับ 1 ตัวแปรซึ่งหมายความว่าไม่มีการเพิ่มประสิทธิภาพหรือจะทำงานกับอาเรย์ มันต้องเปลี่ยนเป็น object (เป็นไปได้ที่จะจัดสรรใหม่)
แกรม Wicksted

2
เช่นเดียวกับคำตอบของ Alex Hawkins โปรดให้คำอธิบายว่าทำไมโค้ดที่ดูค่อนข้างซับซ้อนนี้มีประโยชน์และดีกว่าคำตอบสั้น ๆ อื่น ๆ
Thomas Tempelmann

6

ฉันสร้างสิ่งนี้เพื่อให้เกิดปัญหาบางอย่างเช่นการจับคู่คีย์วัตถุความสามารถในการแจงนับ (พร้อม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)
    ส่งคืนค่าที่เกี่ยวข้องกับคีย์ที่ระบุ
    พารามิเตอร์::
    keyคีย์ที่ดึงค่า

  • put(key, value)
    เชื่อมโยงค่าที่ระบุกับคีย์ที่ระบุ
    พารามิเตอร์::
    keyคีย์ที่เชื่อมโยงค่า
    value: ค่าที่จะเชื่อมโยงกับคีย์

  • remove(key)
    ลบคีย์ที่ระบุด้วยค่าของมัน
    พารามิเตอร์::
    keyกุญแจสำคัญในการลบ

  • clear()
    ล้าง hashtable ทั้งหมดโดยลบทั้งกุญแจและค่า

  • indexOfKey(key)
    ส่งคืนดัชนีของคีย์ที่ระบุตามลำดับการเพิ่ม
    พารามิเตอร์::
    keyคีย์ที่รับดัชนี

  • indexOfValue(value)
    ส่งคืนดัชนีของค่าที่ระบุตามลำดับการเพิ่ม
    พารามิเตอร์::
    valueค่าที่รับดัชนี
    หมายเหตุ:
    ข้อมูลนี้ถูกค้นคืนโดยindexOf()วิธีการของอาเรย์ดังนั้นมันจึงทำการเปรียบเทียบออบเจ็กต์ด้วยtoString()เมธอด

  • entryAt(index)
    ส่งคืนวัตถุที่มีสองคุณสมบัติ: คีย์และค่าแสดงรายการที่ดัชนีที่ระบุ
    พารามิเตอร์::
    indexดัชนีของรายการที่จะได้รับ

  • containsKey(key)
    ส่งคืนว่า hashtable มีคีย์ที่ระบุหรือไม่
    พารามิเตอร์::
    keyกุญแจสำคัญในการตรวจสอบ

  • containsValue(value)
    ส่งคืนว่า hashtable มีค่าที่ระบุหรือไม่
    พารามิเตอร์::
    valueค่าที่จะตรวจสอบ

  • forEach(iterator)
    iterates iteratorรายการทั้งหมดในที่ระบุไว้
    พารามิเตอร์::
    valueวิธีการที่มี 3 พารามิเตอร์: key, valueและindexโดยที่indexแทนดัชนีของรายการ

    คุณสมบัติ:

  • length ( อ่านอย่างเดียว )
    รับจำนวนของรายการใน hashtable

  • keys ( อ่านอย่างเดียว )
    รับอาร์เรย์ของคีย์ทั้งหมดใน hashtable

  • values ( อ่านอย่างเดียว )
    รับอาร์เรย์ของค่าทั้งหมดใน hashtable

  • entries ( อ่านอย่างเดียว )
    รับอาร์เรย์ของรายการทั้งหมดใน hashtable พวกเขากำลังแสดงในรูปแบบของวิธีการentryAt()เดียวกัน


2

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

3
ดูดี. ตอนนี้โปรดอธิบายด้วยว่าทำไมจึงมีประโยชน์และอาจเหมาะสมกว่าคำตอบอื่น ๆ ทั้งหมดที่นี่
Thomas Tempelmann

1

คุณสามารถสร้างได้โดยใช้สิ่งต่อไปนี้:

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)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.