2010-08-23 45 views
20

Javascript中是否有數據結構或模式,可用於快速查找(通過鍵,與關聯數組一樣)和有序循環?用於快速查找和有序循環的Javascript數據結構?

對,現在我正在使用對象文字來存儲我的數據,但我剛發現Chrome瀏覽器在循環訪問屬性名稱時並不維護順序。

有沒有一種常見的方法來解決這個在Javascript中?

感謝您的任何提示。

+2

注意,JavaScript的現在有一個本地'Map'已下令循環。 – 2016-02-05 17:19:19

回答

30

你自己建立一個數據結構。將排序存儲在結構內部的數組中。將由鍵映射的對象存儲在常規對象中。我們稱之爲OrderedMap,它將有一張地圖,一個數組和四個基本方法。

OrderedMap 
    map 
    _array 

    set(key, value) 
    get(key) 
    remove(key) 
    forEach(fn) 

function OrderedMap() { 
    this.map = {}; 
    this._array = []; 
} 

當插入一個元素時,將它添加到數組中的所需位置以及對象。按索引插入或在最後插入O(1)。

OrderedMap.prototype.set = function(key, value) { 
    // key already exists, replace value 
    if(key in this.map) { 
     this.map[key] = value; 
    } 
    // insert new key and value 
    else { 
     this._array.push(key); 
     this.map[key] = value; 
    } 
}; 

刪除對象時,將其從數組和對象中刪除。如果通過鍵或值刪除,複雜度爲O(n),因爲您需要遍歷維持排序的內部數組。按索引刪除時,複雜度爲O(1),因爲您可以直接訪問數組和對象中的值。

OrderedMap.prototype.remove = function(key) { 
    var index = this._array.indexOf(key); 
    if(index == -1) { 
     throw new Error('key does not exist'); 
    } 
    this._array.splice(index, 1); 
    delete this.map[key]; 
}; 

查找將在O(1)中。通過關聯數組(對象)中的鍵檢索值。

OrderedMap.prototype.get = function(key) { 
    return this.map[key]; 
}; 

遍歷將被排序並且可以使用任一種方法。當需要有序遍歷時,使用對象(僅限值)創建一個數組並返回它。作爲一個數組,它不支持鍵控訪問。另一種選擇是要求客戶端提供一個應用於數組中每個對象的回調函數。

OrderedMap.prototype.forEach = function(f) { 
    var key, value; 
    for(var i = 0; i < this._array.length; i++) { 
     key = this._array[i]; 
     value = this.map[key]; 
     f(key, value); 
    } 
}; 

見谷歌的實施LinkedMap從Closure庫的文檔和源這樣的類。

+0

很好的答案,謝謝。 – Haes 2010-08-24 07:07:31

+0

如何查找O(1)?如果您使用的不是數組索引,則JS屬性解析爲O(n)(它必須通過循環遍歷原型鏈來解決)。請參閱http://bonsaiden.github.io/JavaScript-Garden/上的Property Lookup。 – ginman 2014-11-05 20:23:33

+4

事實上,它必須遍歷原型鏈仍然不會使它O(n)。設想一個4級深度的原型鏈層次結構,每個層次都維護一個散列結構來保存鍵和值。那麼它只需要平均4個這樣的O(1)查找。這仍然是O(1)。現在,據我所知,ECMAScript沒有要求實現細節,所以如果他們願意,可以在O(n²)中執行。換句話說,它是依賴於實現的,但是如果給出最正常的實現,則可以期望平均進行O(1)查找。 – Anurag 2014-11-05 23:40:40

3

Chrome不維護對象文字中鍵的順序的唯一實例似乎是鍵是數字的情況。

var properties = ["damsonplum", "9", "banana", "1", "apple", "cherry", "342"]; 
    var objLiteral = { 
    damsonplum: new Date(), 
    "9": "nine", 
    banana: [1,2,3], 
    "1": "one", 
    apple: /.*/, 
    cherry: {a: 3, b: true}, 
    "342": "three hundred forty-two" 
    } 
    function load() { 
    var literalKeyOrder = []; 
    for (var key in objLiteral) { 
     literalKeyOrder.push(key); 
    } 

    var incremental = {}; 
    for (var i = 0, prop; prop = properties[i]; i++) { 
     incremental[prop] = objLiteral[prop]; 
    } 

    var incrementalKeyOrder = []; 
    for (var key in incremental) { 
     incrementalKeyOrder.push(key); 
    } 
    alert("Expected order: " + properties.join() + 
      "\nKey order (literal): " + literalKeyOrder.join() + 
      "\nKey order (incremental): " + incrementalKeyOrder.join()); 
    } 

在Chrome中,上述產生:「1,9342,damsonplum,香蕉,蘋果,櫻桃」。

在其他瀏覽器中,它產生「damsonplum,9,香蕉,1,蘋果,櫻桃,342」。

所以,除非你的鑰匙是數字,我想即使在Chrome中,你是安全的。如果你的密鑰是數字的,也許只是用一個字符串預先給它們。

+1

這是否適用於V8,因此也適用於Node.js? – 2014-04-17 10:04:44

2

作爲 has been noted,如果你的密鑰是數字 你可以用一個字符串來預先保存它們的順序。

var qy = { 
    _141: '256k AAC', 
    _22: '720p H.264 192k AAC', 
    _84: '720p 3D 192k AAC', 
    _140: '128k AAC' 
}; 

Example