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

问题描述 投票:0回答:6

给定一个键,我想找到对象中的下一个属性。我不能依赖键来排序或顺序(它们是 uuid)。请参阅下面的简单示例,了解我想要的内容:

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编写的解决方案:)

javascript json coffeescript underscore.js
6个回答
31
投票

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

 let keys = Object.keys(storeObject);
 let nextItem = keys.at(keys.indexOf(theCurrentItem) +1);

23
投票

正确的答案是:你不能这样做,因为根据 ECMAScript 的规范,对象是无序的。

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

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
 来简化该函数。

您还可以使用一些 Underscore.js 实用方法来使

next

 更简单:

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

 循环来迭代它。我建议使用 
Object.keys
 来简化迭代数组的工作:

// 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]]; };
    

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

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

 不需要按照添加键的顺序(尽管在实践中,这往往是常见的实现)。在此解决方案中,我使用数组来显式跟踪插入顺序。

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

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

3
投票
使用 undercore.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/


1
投票
我于 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));
    
© www.soinside.com 2019 - 2024. All rights reserved.