Étant donné une clé, je veux trouver la propriété suivante dans un objet. Je ne peux pas me fier aux clés à ordonner ou séquentielles (ce sont des uuides). Veuillez voir ci-dessous pour un exemple trivial de ce que je veux:
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
Je veux aussi une fonction prev (), mais je suis sûr que ce sera la même solution.
Cela semble être un problème si trivial, mais je ne peux pas pour la vie de moi comprendre comment le faire.
Heureux que la solution utilise underscore.js ou soit écrite en coffeescript :)
La bonne réponse est: vous ne pouvez pas faire cela, car les objets ne sont pas ordonnés selon les spécifications d'ECMAScript .
Je vous recommande d'utiliser une structure ordonnée, comme un tableau, aux fins du problème:
var db = [
{key: 'a', value: 1},
{key: 'b', value: 2},
{key: 'c', value: 3}
];
Ensuite, la fonction next
peut être quelque chose comme:
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;
}
}
};
Si key
n'existe pas sur db
ou si c'était le dernier, next
renvoie undefined
. si vous n'allez jamais demander le suivant du dernier élément, vous pouvez simplifier cette fonction en supprimant le ternaire &&
opérateur et retour de db[i + 1].value
directement.
Vous pouvez également utiliser certaines des méthodes utilitaires Underscore.js pour simplifier next
:
var next = function(db, key) {
var i = _.pluck(db, 'key').indexOf(key);
return i !== -1 && db[i + 1] && db[i + 1].value;
};
(dans ce cas next
pourrait renvoyer false
parfois ... mais c'est toujours une valeur fausse :))
Maintenant, une réponse plus pragmatique pourrait être que, comme la plupart des navigateurs respecteront l'ordre dans lequel un objet a été initialisé lors de son itération, vous pouvez simplement l'itérer avec un for in
boucle comme le suggèrent les autres réponses. Je recommanderais d'utiliser Object.keys
pour simplifier le travail d'itération sur le tableau:
// 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]];
};
version ts/es6. J'obtiens simplement les clés du storeObject, cherche l'index suivant.
let keys = Object.keys(storeObject);
let nextIndex = keys.indexOf(theCurrentItem) +1;
let nextItem = keys[nextIndex];
function next(db, key){
var found = 0;
for(var k in db){
if(found){ return db[k]; }
if(k == key){ found = 1; }
}
}
Une solution immédiate à cela serait de stocker les données dans un tableau et d'utiliser l'objet pour simplement stocker l'index dans le tableau dans lequel un objet existe.
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;
}
}
}
}
L'idée de base est d'utiliser une structure ordonnée, dans ce cas le tableau, pour contenir les données de manière séquentielle. Dans ce cas, next et prev sont tous deux des temps constants, add est un temps constant amorti et delete est O (N).
L'ordre des clés n'est pas garanti par la norme ECMA, donc for/in
n'a pas besoin d'être dans l'ordre où les clés ont été ajoutées (bien qu'en pratique, cela ait tendance à être l'implémentation courante). Dans cette solution, j'utilise un tableau pour suivre explicitement l'ordre d'insertion.
Edit: J'ai négligé un problème de suppression plus tôt avec l'épissure. L'index deviendrait incorrect pour toutes les valeurs après la valeur épissée pour une suppression. Le correctif n'a pas d'impact sur la complexité du temps d'exécution de l'opération. Une version plus rapide avec moins de suppressions pourrait laisser le tableau devenir clairsemé et au lieu d'épisser, définissez simplement l'index sur null pour libérer toute référence qui y est stockée. Cela abaisserait l'opération de suppression à O (1).
function remove(db, key) {
var index = db.index[key];
if (index !== undefined) {
delete db.index[key];
db.data[index] = null;
}
}
En utilisant undercore.js, vous pouvez prendre les clés d'un objet et faire l'affaire. Mais je ne sais pas si les paires clé-valeur sont ordonnées de quelque manière que ce soit pour commencer:
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/