cap*_*lam 20 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
Run Code Online (Sandbox Code Playgroud)
我也想要一个prev()函数,但我相信它将是相同的解决方案.
这似乎是一个微不足道的问题,但我不能为我的生活弄清楚如何去做.
很高兴使用underscore.js的解决方案或写在coffeescript :)
epi*_*ian 20
正确答案是:你不能这样做,因为根据ECMAScript的规范,对象是无序的.
我建议您使用有序的结构,如数组,以解决问题:
var db = [
{key: 'a', value: 1},
{key: 'b', value: 2},
{key: 'c', value: 3}
];
Run Code Online (Sandbox Code Playgroud)
那么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;
}
}
};
Run Code Online (Sandbox Code Playgroud)
如果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;
};
Run Code Online (Sandbox Code Playgroud)
(在这种情况下有时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]];
};
Run Code Online (Sandbox Code Playgroud)
ts / es6版本。我只是从storeObject获取密钥,寻找下一个索引。
let keys = Object.keys(storeObject);
let nextIndex = keys.indexOf(theCurrentItem) +1;
let nextItem = keys[nextIndex];
Run Code Online (Sandbox Code Playgroud)
function next(db, key){
var found = 0;
for(var k in db){
if(found){ return db[k]; }
if(k == key){ found = 1; }
}
}
Run Code Online (Sandbox Code Playgroud)
对此的直接解决方案是将数据存储在数组中,并使用该对象将索引简单地存储在对象所在的数组中.
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;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
基本思想是使用有序结构(在本例中为数组)以顺序方式保存数据.在这种情况下,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;
}
}
Run Code Online (Sandbox Code Playgroud)