web-dev-qa-db-fra.com

Obtenir la prochaine paire clé-valeur dans un objet

É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 :)

20
captainclam

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]];
};
19
epidemian

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];
8
httpete
function next(db, key){   
  var found = 0; 
  for(var k in db){
    if(found){ return db[k]; }
    if(k == key){ found = 1; }
  }
}
6
anson

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;
    }
}
5
Justin Summerlin

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/

3
janith