用于快速查找和有序循环的Javascript数据结构?

时间:2010-08-23 17:05:35

标签: javascript loops object-literal

Javascript中是否有数据结构或模式可用于快速查找(按键,如关联数组)和有序循环?

是的,现在我使用对象文字来存储我的数据,但我发现Chrome在循环遍历属性名称时没有维护顺序。

有没有一种常见的方法可以在Javascript中解决这个问题?

感谢任何提示。

3 个答案:

答案 0 :(得分:33)

自己创建数据结构。将排序存储在结构内部的数组中。将键映射的对象存储在常规对象中。我们称之为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);
    }
};

请参阅Google在Closure Library中对LinkedMap的实现,以获取此类的文档和来源。

答案 1 :(得分: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,banana,1,apple,cherry,342”。

因此,除非您的密钥是数字的,否则我认为即使在Chrome中,您也是安全的。如果您的密钥是数字的,可能只是用字符串前缀。

答案 2 :(得分:2)

作为 has been noted,如果您的密钥是数字的 你可以用字符串前缀它们以保持秩序。

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

Example