Obtener el siguiente par key-valor en un object

Dada una key, quiero encontrar la siguiente propiedad en un object. No puedo confiar en que las keys sean orderadas o secuenciales (son uuids). Vea a continuación un ejemplo trivial de lo que quiero:

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 

También quiero una function prev (), pero estoy seguro de que será la misma solución.

Esto parece un problema tan trivial, pero no puedo imaginar cómo hacerlo.

Feliz por la solución para usar underscore.js o estar escrito en coffeescript 🙂

La respuesta correcta es: no puede hacer eso, ya que los objects no están orderados según las especificaciones de ECMAScript .

Le recomendaría que use una estructura orderada, como una matriz, para el propósito del problema:

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

Entonces la next function puede ser algo así como:

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

En caso de que la key no exista en db o sea la última, la next devuelve undefined . si nunca va a pedir el siguiente del último elemento, puede simplificar esa function eliminando el operador ternario && y devolviendo db[i + 1].value directamente.

También puede usar algunos de los methods de utilidad de Underscore.js para simplificar el next :

 var next = function(db, key) { var i = _.pluck(db, 'key').indexOf(key); return i !== -1 && db[i + 1] && db[i + 1].value; }; 

(en este caso el next podría volverse false veces … pero sigue siendo un valor falso :))


Ahora, una respuesta más pragmática podría ser que, como la mayoría de los browseres respetarán el order en el que se inicializó un object al iterarlo, puede iterarlo con un bucle for in como sugieren las otras respuestas. Recomiendo usar Object.keys para simplificar el trabajo de iterar sobre la matriz:

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

Una solución inmediata a esto sería almacenar datos en una matriz y usar el object para simplemente almacenar el índice en la matriz en la que existe un object.

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

La idea básica es usar una estructura orderada, en este caso la matriz, para contener los datos de forma secuencial. En este caso, next y prev son ambos time constante, add es time constante amortizado y delete es O (N).

El order de las keys no está garantizado por el estándar ECMA, for/in lo que for/in no tiene que estar en el order en que se agregaron las keys (aunque en la práctica, eso tiende a ser la implementación común). En esta solución, utilizo una matriz para realizar un seguimiento explícito de la order de inserción.

Editar: Pasé por alto un problema de eliminación anterior con empalme. El índice se volvería incorrecto para todos los valores después del valor empalmado para una eliminación. La solución no afecta la complejidad del time de ejecución de la operación. Una versión más rápida con less eliminaciones podría dejar que la matriz se vuelva escasa y en lugar de empalmar, simplemente configure el índice como nulo para liberar cualquier reference almacenada allí. Esto networkinguciría la operación de eliminación a O (1).

 function remove(db, key) { var index = db.index[key]; if (index !== undefined) { delete db.index[key]; db.data[index] = null; } } 
 function next(db, key){ var found = 0; for(var k in db){ if(found){ return db[k]; } if(k == key){ found = 1; } } } 

Usando undercore.js, puedes tomar las llaves de un object y hacer el truco. Pero no estoy seguro de si los pares key-valor están orderados de alguna manera para comenzar:

 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/

ts / versión es6. Simplemente obtengo las keys de storeObject, busco el siguiente índice.

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