获取对象中的下一个键值对

时间:2012-09-20 03:10:37

标签: javascript json coffeescript underscore.js

给定一个键,我想找到一个对象中的下一个属性。我不能依赖按键来订购或顺序(它们是uuids)。请看下面我想要的简单示例:

var db = {
  a: 1,
  b: 2,
  c: 3
}

var next = function(db, key) {
  // ???
}

next(db, 'a');  // I want 2
next(db, 'b');  // I want 3

我也想要一个prev()函数,但我确信它将是相同的解决方案。

这似乎是一个微不足道的问题,但我不能为我的生活弄清楚如何去做。

对于使用underscore.js或使用coffeescript编写的解决方案感到高兴:)

6 个答案:

答案 0 :(得分:17)

正确的答案是:你不能这样做,objects are unordered as per ECMAScript's spec

我建议您使用有序的结构(如数组)来解决问题:

var db = [
  {key: 'a', value: 1},
  {key: 'b', value: 2},
  {key: 'c', value: 3}
];

然后next函数可以是:

var next = function(db, key) {
  for (var i = 0; i < db.length; i++) {
    if (db[i].key === key) {
      return db[i + 1] && db[i + 1].value;
    }
  }
};

如果key上不存在db或最后一个next,则undefined会返回&&。如果您永远不会要求下一个最后一项,则可以通过删除三元db[i + 1].value运算符并直接返回next来简化该功能。

您还可以使用一些Underscore.js实用程序方法使var next = function(db, key) { var i = _.pluck(db, 'key').indexOf(key); return i !== -1 && db[i + 1] && db[i + 1].value; }; 更简单:

next

(在这种情况下false有时会返回for in ......但它仍然是一个假值:))


现在,一个更实用的答案可能是,因为大多数浏览器都会尊重对象在迭代时初始化的顺序,所以你可以像其他答案建议的那样用// Assuming that db is an object as defined in the question. var next = function(db, key) { var keys = Object.keys(db) , i = keys.indexOf(key); return i !== -1 && keys[i + 1] && db[keys[i + 1]]; }; 循环迭代它。我建议使用Object.keys来简化迭代数组的工作:

{{1}}

答案 1 :(得分:6)

function next(db, key){   
  var found = 0; 
  for(var k in db){
    if(found){ return db[k]; }
    if(k == key){ found = 1; }
  }
}

答案 2 :(得分:5)

立即解决此问题的方法是将数据存储在数组中,并使用该对象将索引存储在对象所在的数组中。

var db = {
    data: [1, 2, 3],
    index: {
        a: 0,
        b: 1,
        c: 2
    }
};
function next(db, key) {
    var next = db.index[key] + 1;
    if (next >= db.data.length) {
        return null;
    }
    return db.data[next];
}
function prev(db, key) {
    var next = db.index[key] - 1;
    if (next < 0) {
        return null;
    }
    return db.data[next];
}
function add(db, key, value) {
    db.index[key] = db.data.push(value) - 1;
}
function remove(db, key) {
    var index = db.index[key], x, temp;
    if (index !== undefined) {
        delete db.index[key];
        db.data.splice(index, 1);
        // Update indices of any elements after the removed element
        for (x in db.index) {
            temp = db.index[x];
            if (temp > index) {
                db.index[x] = temp - 1;
            }
        }
    }
}

基本思想是使用有序结构(在本例中为数组)以顺序方式保存数据。在这种情况下,next和prev都是常量时间,add是摊销的常量时间,delete是O(N)。

ECMA标准无法保证密钥的排序,因此for/in不需要添加密钥(尽管在实践中,这往往是常见的实现)。在此解决方案中,我使用数组来明确跟踪插入顺序。

编辑:我之前忽略了splice的删除问题。在删除的拼接值之后,索引将对所有值都不正确。该修复不会影响操作的运行时复杂性。删除较少的更快版本可以让数组变得稀疏而不是拼接,只需将索引设置为null即可释放存储在那里的任何引用。这会将删除操作降低到O(1)。

function remove(db, key) {
    var index = db.index[key];
    if (index !== undefined) {
        delete db.index[key];
        db.data[index] = null;
    }
}

答案 3 :(得分:5)

ts / es6版本。我只是从storeObject获取键,寻找下一个索引。

 let keys = Object.keys(storeObject);
 let nextIndex = keys.indexOf(theCurrentItem) +1;
 let nextItem = keys[nextIndex];

答案 4 :(得分:3)

使用underscore.js,您可以获取对象的键并执行操作。但我不确定键值对是否以任何方式排序开始:

var next = function(db, key) {
    var keys = _.keys(db);
    var index = _.indexOf(keys, key);
    if(index+1<keys.length){
         return db[keys[index+1]];
    }else{
        return null;
    }
}

jsFiddle:http://jsfiddle.net/QWhN2/

答案 5 :(得分:0)

我于 2021 年来到这里,所以我会发布一个 Es6 解决方案。

一个简单的解决方案,让您在给定起始键的情况下导航对象:

const navObj = (obj, currentKey, direction) => {
    return Object.values(obj)[Object.keys(obj).indexOf(currentKey) + direction];
};

const db = {
  a: 1,
  b: 2,
  c: 3
};

console.log(navObj(db, 'a', 1));
console.log(navObj(db, 'a', 2));
console.log(navObj(db, 'b', -1));