1952 votes

Trouver un objet par son identifiant dans un tableau d'objets JavaScript

J'ai un tableau :

myArray = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'}, etc.]

Je ne parviens pas à modifier la structure du tableau. On me passe un id de 45 et je veux obtenir 'bar' pour cet objet dans le tableau.

Comment puis-je faire cela en JavaScript ou en utilisant jQuery ?

1491voto

Guffa Points 308133

Comme vous utilisez déjà jQuery, vous pouvez utiliser la fonction grep qui est destinée à la recherche dans un tableau :

var result = $.grep(myArray, function(e){ return e.id == id; });

Le résultat est un tableau contenant les éléments trouvés. Si vous savez que l'objet est toujours là et qu'il n'apparaît qu'une seule fois, vous pouvez simplement utiliser result[0].foo pour obtenir la valeur. Sinon, vous devez vérifier la longueur du tableau résultant. Exemple :

if (result.length === 0) {
  // no result found
} else if (result.length === 1) {
  // property found, access the foo property using result[0].foo
} else {
  // multiple items found
}

132 votes

Il serait plus sûr d'utiliser === au lieu de == afin d'éviter des problèmes bizarres avec le langage JavaScript == opérateur.

11 votes

@VickyChijwani : Y a-t-il des problèmes lors de la comparaison d'une chaîne à une chaîne ?

41 votes

Eh bien, si vous êtes absolument s'assurer que les deux e.id y id seront des chaînes de caractères, je suppose qu'il est possible d'utiliser des == . Mais si vous n'êtes pas sûr, vous risquez de rencontrer des problèmes (puisque '' == 0 es true mais '' === 0 es false ). Sans oublier === semble être plus rapide ( stackoverflow.com/questions/359494/ ).

371voto

Aaron Digulla Points 143830

Une autre solution consiste à créer un objet de consultation :

var lookup = {};
for (var i = 0, len = array.length; i < len; i++) {
    lookup[array[i].id] = array[i];
}

... now you can use lookup[id]...

Ceci est particulièrement intéressant si vous devez effectuer de nombreuses recherches.

Cela ne nécessitera pas beaucoup plus de mémoire puisque les identifiants et les objets seront partagés.

6 votes

Exactement ce que je cherchais. C'est drôle comme j'essayais de compliquer les choses à l'excès en essayant de boucler à chaque fois, en supprimant chaque élément de la liste au fur et à mesure que je le trouvais alors que j'avais seulement besoin de muter les données reçues de CouchDB et de les mettre dans un format utile pour mes besoins. +1 monsieur !

5 votes

C'est intelligent. Je ne peux pas imaginer comment les autres ont été convaincus en regardant partout dans le tableau pour chaque utilisation.

4 votes

Tant que vous ne vous fiez pas à l'ordre des propriétés : stackoverflow.com/questions/4886314/

145voto

GijsjanB Points 2604

Underscore.js a une bonne méthode pour cela :

myArray = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'},etc.]
obj = _.find(myArray, function(obj) { return obj.id == '45' })

44 votes

Pour mémoire, Lo-Dash (qui est souvent manifestement plus performant qu'Underscore) a une méthode similaire. Docs ici : lodash.com/docs#find

0 votes

Si vous n'attendez qu'un seul objet, l'utilisation de findWhere sera plus efficace, car après avoir trouvé un résultat, la recherche ne se poursuivra pas.

0 votes

@Foreever Extrait de la docs de _.find : "La fonction revient dès qu'elle trouve un élément acceptable, et ne parcourt pas toute la liste."

139voto

pimvdb Points 66332

Je pense que la méthode la plus simple serait la suivante, mais elle ne fonctionnera pas sur Internet Explorer 8 (ou antérieur) :

var result = myArray.filter(function(v) {
    return v.id === '45'; // Filter out the appropriate one
})[0].foo; // Get result and access the foo property

0 votes

Je suis curieux, y a-t-il un avantage de performance par rapport à l'habituel for ?

0 votes

@Igor Zinov'yev : Oui, il y a certainement des impacts sur les performances avec ces outils de tableau ES5. Une fonction distincte est exécutée pour chaque élément, donc ce ne sera pas vraiment rapide par rapport à une utilisation directe de la fonction for boucle.

0 votes

Donc vous dites que ce serait plus lent ? De plus, il balayera toujours l'ensemble du tableau, d'après ce que je peux voir, alors que la fonction for La boucle se terminera au premier résultat.

77voto

JaredPar Points 333733

Essayez ce qui suit

function findById(source, id) {
  for (var i = 0; i < source.length; i++) {
    if (source[i].id === id) {
      return source[i];
    }
  }
  throw "Couldn't find object with id: " + id;
}

18 votes

Cela ne méritait pas une réponse à part entière, mais dans les navigateurs modernes, cette solution peut être écrite comme suit : jsfiddle.net/rwaldron/j3vST

13 votes

Si vous recherchez l'efficacité, notez que cet exemple est probablement plus rapide que l'utilisation de filter() (voir l'exemple de Rick) puisque celui-ci renvoie une fois qu'il a trouvé le premier élément correspondant alors que filter() continue à parcourir le tableau complet même après avoir trouvé une correspondance. Cet exemple n'a pas non plus le coût de la création d'un tableau supplémentaire ou de l'appel d'une fonction pour chaque élément.

3 votes

@Rick, la chose la plus intéressante dans cette réponse est qu'apparemment vous pouvez ajouter la console firebug à la fenêtre de sortie dans jsFiddle. C'est tellement mieux que de journaliser et de dire à quelqu'un d'autre d'ouvrir la console pour voir la sortie. Génial !

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X