Rechercher un objet par id dans un tableau d'objets JavaScript

1547

J'ai un tableau:

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

Je ne parviens pas à modifier la structure du tableau. Je reçois un identifiant de 45, et je veux obtenir 'bar'cet objet dans le tableau.

Comment faire cela en JavaScript ou en utilisant jQuery?

voyou
la source

Réponses:

1193

Utilisez la find()méthode:

myArray.find(x => x.id === '45').foo;

De MDN :

La find()méthode renvoie la première valeur du tableau si un élément du tableau satisfait la fonction de test fournie. Sinon undefinedest retourné.


Si vous souhaitez plutôt trouver son index , utilisezfindIndex() :

myArray.findIndex(x => x.id === '45');

De MDN :

le findIndex() méthode renvoie l'index du premier élément du tableau qui satisfait la fonction de test fournie. Sinon, -1 est renvoyé.


Si vous souhaitez obtenir un tableau d'éléments correspondants, utilisez le filter() plutôt méthode:

myArray.filter(x => x.id === '45');

Cela renverra un tableau d'objets. Si vous souhaitez obtenir un tableau de foopropriétés, vous pouvez le faire avec la map()méthode:

myArray.filter(x => x.id === '45').map(x => x.foo);

Remarque: les méthodes comme find()ou filter()et les fonctions fléchées ne sont pas prises en charge par les anciens navigateurs (comme IE), donc si vous souhaitez prendre en charge ces navigateurs, vous devez transpiler votre code à l'aide de Babel (avec le polyfill ).

Michał Perłakowski
la source
2
Pour de multiples conditions de test, ce serait donc quelque chose comme: myArray.find (x => x.id === '45' && x.color == 'red'). Foo
Apqu
2
Pour moi, la meilleure réponse jusqu'à présent. N'a pas besoin de jQuery ni de créer de nouveaux tableaux auxiliaires.
Canta
myArray.find (x => x.id === '45') cela ne fonctionne pas sur mac PC
Govinda Rajbhar
@TJCrowder Je ne pense pas que ce soit une bonne idée de copier-coller des polyfills de MDN dans votre code; à la place, vous devez utiliser des packages npm avec des polyfills. Et Babel inclut des polyfills pour les fonctionnalités ES2015 +, dans le package babel-polyfill .
Michał Perłakowski
2
myArray.find (x => x.id === '45'). foo; lève une exception s'il n'y a aucun objet avec un identifiant de '45'.
Frazer Kirkman
1466

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

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

Le résultat est un tableau avec les éléments trouvés. Si vous savez que l'objet est toujours là et qu'il ne se produit qu'une seule fois, vous pouvez simplement utiliser result[0].foopour 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
}
Guffa
la source
124
Il serait plus sûr d'utiliser à la ===place de ==, pour éviter des problèmes étranges avec l' ==opérateur JavaScript .
Vicky Chijwani
11
@VickyChijwani: Y a-t-il des problèmes lors de la comparaison d'une chaîne à une chaîne?
Guffa
38
Eh bien, si vous êtes absolument sûr que les deux e.idet idseront des chaînes, je suppose qu'il est autorisé à utiliser ==. Mais si vous n'êtes pas sûr, vous pourriez rencontrer des problèmes (puisque '' == 0c'est truemais '' === 0est false). Sans oublier qu'il ===semble être plus rapide ( stackoverflow.com/questions/359494/… ).
Vicky Chijwani
101
En gros, je l'utilise toujours ===car il fonctionne exactement comme ==dans d'autres langages de programmation. Je considère ==comme inexistant en JavaScript.
Vicky Chijwani
6
@de. De nombreuses réponses ici fournissent le comportement souhaité lors de la recherche de valeurs uniques; vous pouvez essentiellement les reconnaître par le fait qu'ils reviennent ou se cassent tôt de leur boucle (ou ordonnent à une construction de niveau inférieur d'arrêter l'itération). Voir la réponse de JaredPar pour un exemple canonique, et le commentaire d'Aaronius sur cette réponse pour le même aperçu. En général, les gens font la différence entre les fonctions "filtrer" et "trouver" de cette manière, mais la terminologie varie. Bien que plus efficace, il s'agit toujours d'une recherche linéaire, donc si vous souhaitez utiliser une table de hachage, voir la réponse d'Aaron Digulla (méfiez-vous des détails implicites).
TNE
362

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

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 n'aura pas besoin de beaucoup plus de mémoire car les ID et les objets seront partagés.

Aaron Digulla
la source
6
Exactement ce que je cherchais. C'est drôle comme j'essayais de le compliquer en essayant de parcourir chaque fois, en supprimant chaque élément de la liste tel que je l'ai trouvé lorsque je n'avais besoin que de muter les données reçues de CouchDB et de les mettre dans un format utile pour mon Besoins. +1 monsieur!
slickplaid
5
c'est intelligent. Je ne peux pas imaginer comment les autres ont été convaincus en regardant partout dans le tableau pour chaque utilisation.
Aladdin Mhemed
4
Tant que vous ne comptez pas sur l'ordre des propriétés: stackoverflow.com/questions/4886314/…
Marle1
Utilise une pause; dans la boucle une bonne option / amélioration si vous savez qu'il n'y a qu'un seul objet à trouver?
irJvV
7
@irJvV: Non, cela n'a aucun sens. Le code ci-dessus est utile si vous devez effectuer de nombreuses recherches. Si vous ne regardez qu'une seule fois, la création d'un lookupobjet est une perte de temps.
Aaron Digulla
174

ECMAScript 2015 fournit la méthode find () sur les tableaux:

var myArray = [
 {id:1, name:"bob"},
 {id:2, name:"dan"},
 {id:3, name:"barb"},
]

// grab the Array item which matchs the id "2"
var item = myArray.find(item => item.id === 2);

// print
console.log(item.name);

Il fonctionne sans bibliothèques externes. Mais si vous voulez un support de navigateur plus ancien, vous voudrez peut-être inclure ce polyfill .

Rúnar Berg
la source
1
Probablement parce qu'il semble toujours très expérimental et que peu de navigateurs le supportent, developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
lejonl
2
Cela peut être simplifié myArray.find(d=>d.id===45).foo;.
Shaggy
1
@Shaggy ou même myArray.find(({ id }) => id === 45).foo. Mais c'est une ancienne réponse qui a été écrite avant que la syntaxe ES2015 ne soit aussi bien prise en charge que maintenant. La réponse de @ Gothdo est actuellement la plus récente du fil.
Rúnar Berg
1
@Shaggy si le .find () renvoie undefined, alors votre optimisation génère une erreur. Cette solution ne peut donc être utilisée que dans les cas où une correspondance est garantie.
Herbert Peters
1
@HerbertPeters Si vous voulez être sûr que vous pouvez alway-chèque nul, qui sera vraiment facile avec Enchaînement en option : myArray.find(d => d.id === 45)?.foo.
Rúnar Berg
141

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

myArray = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'},etc.]
obj = _.find(myArray, function(obj) { return obj.id == '45' })
GijsjanB
la source
42
Pour mémoire, Lo-Dash (qui est souvent manifestement plus performant que Underscore) a une méthode similaire. Documents ici: lodash.com/docs#find
user456584
Si vous n'attendez qu'un seul objet, alors l'utilisation de findWhere serait plus efficace car après avoir trouvé un résultat, la recherche n'irait pas plus loin.
Forever
@Foreever D'après les documents de _.find: "La fonction retourne dès qu'elle trouve un élément acceptable et ne traverse pas la liste entière."
GijsjanB
129

Je pense que le moyen le plus simple serait le suivant, mais cela ne fonctionnera pas sur Internet Explorer 8 (ou version antérieure):

var result = myArray.filter(function(v) {
    return v.id === '45'; // Filter out the appropriate one
})[0].foo; // Get result and access the foo property
pimvdb
la source
Je suis curieux, y a-t-il un avantage de performance ici par rapport à l'habituel for?
Igor Zinov'yev,
@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, elle ne sera donc pas vraiment rapide par rapport à une forboucle directe .
pimvdb
Vous dites donc que ce serait plus lent? En outre, il analysera toujours l'ensemble du tableau, pour autant que je puisse voir, tandis que la forboucle se terminera lors de la première correspondance.
Igor Zinov'yev
Si vous avez besoin de support pour IE8, déposez-le simplement dans: stackoverflow.com/questions/7153470/…
Adam Grant
Ce code générera une erreur s'il n'y a aucun élément avec celaid
Stan
71

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;
}
JaredPar
la source
17
Ce n'était pas digne de sa propre réponse, mais dans les navigateurs modernes, cette solution peut être écrite comme: jsfiddle.net/rwaldron/j3vST
Rick
12
Si vous optez pour l'efficacité, notez que cet exemple est probablement plus rapide que d'utiliser filter () (voir l'exemple de Rick) car celui-ci revient une fois qu'il trouve le premier élément correspondant tandis que filter () continue de parcourir le tableau complet même après avoir trouvé un rencontre. Celui-ci n'a pas non plus le coût de créer un tableau supplémentaire ou d'appeler une fonction pour chaque élément.
Aaronius
3
@Rick, la chose la plus intéressante à propos de cette réponse est que vous pouvez apparemment ajouter la console Firebug à la fenêtre de sortie dans jsFiddle. C'est tellement mieux que de se connecter et de dire à quelqu'un d'autre d'ouvrir la console pour voir la sortie. Impressionnant!
KyleMit
1
Comme personne ne l'a mentionné jusqu'à présent, je voulais ajouter que AngularJS a également une méthode de filtrage .
Eno
31

Une version générique et plus flexible de la fonction findById ci-dessus:

// array = [{key:value},{key:value}]
function objectFindByKey(array, key, value) {
    for (var i = 0; i < array.length; i++) {
        if (array[i][key] === value) {
            return array[i];
        }
    }
    return null;
}

var array = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'}];
var result_obj = objectFindByKey(array, 'id', '45');
Farrell
la source
15

Vous pouvez l'obtenir facilement en utilisant la fonction map () :

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

var found = $.map(myArray, function(val) {
    return val.id == 45 ? val.foo : null;
});

//found[0] == "bar";

Exemple de travail: http://jsfiddle.net/hunter/Pxaua/

chasseur
la source
1
J'ai oublié le fait que jQuery mapsupprime automatiquement les nulléléments. Cela semble trompeur pour moi et pour le concept commun de map, car le résultat n'est pas de la même longueur que la collection originale.
MaxArt
14

Vous pouvez utiliser des filtres,

  function getById(id, myArray) {
    return myArray.filter(function(obj) {
      if(obj.id == id) {
        return obj 
      }
    })[0]
  }

get_my_obj = getById(73, myArray);
Joe Lewis
la source
1
@TobiasBeuving - Celui qui utilise Array.find () est également du JS simple et devrait s'arrêter à la première recherche, ce qui sera plus efficace.
Adrian Lynch
12

Bien qu'il existe de nombreuses réponses correctes ici, beaucoup d'entre elles n'abordent pas le fait qu'il s'agit d'une opération inutilement coûteuse si elle est effectuée plusieurs fois. Dans un cas extrême, cela pourrait être la cause de réels problèmes de performances.

Dans le monde réel, si vous traitez beaucoup d'éléments et que les performances sont une préoccupation, il est beaucoup plus rapide de créer initialement une recherche:

var items = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'}];

var lookup = items.reduce((o,i)=>o[i.id]=o,{});

vous pouvez ensuite accéder aux éléments dans un délai fixe comme celui-ci:

var bar = o[id];

Vous pouvez également envisager d'utiliser une carte au lieu d'un objet comme recherche: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Map

À M
la source
11

Utilisation native Array.reduce

var array = [ {'id':'73' ,'foo':'bar'} , {'id':'45' ,'foo':'bar'} , ];
var id = 73;
var found = array.reduce(function(a, b){
    return (a.id==id && a) || (b.id == id && b)
});

renvoie l'élément objet s'il est trouvé, sinon false

laggingreflex
la source
Juste une note, Array.reduce n'est pas pris en charge dans IE8 et sous.
Burn_E99
7

Si vous effectuez cette opération plusieurs fois, vous pouvez configurer une carte (ES6):

const map = new Map( myArray.map(el => [el.id, el]) );

Ensuite, vous pouvez simplement faire:

map.get(27).foo
Jonas Wilms
la source
6

Voici comment j'y arriverais en JavaScript pur, de la manière la plus minimale que je puisse penser qui fonctionne dans ECMAScript 3 ou version ultérieure. Il revient dès qu'une correspondance est trouvée.

var getKeyValueById = function(array, key, id) {
    var testArray = array.slice(), test;
    while(test = testArray.pop()) {
        if (test.id === id) {
            return test[key];
        }
    }
    // return undefined if no matching id is found in array
    return;
}

var myArray = [{'id':'73', 'foo':'bar'}, {'id':'45', 'foo':'bar'}]
var result = getKeyValueById(myArray, 'foo', '45');

// result is 'bar', obtained from object with id of '45'
Dan W
la source
5

Plus générique et court

function findFromArray(array,key,value) {
        return array.filter(function (element) {
            return element[key] == value;
        }).shift();
}

dans votre cas Ex. var element = findFromArray(myArray,'id',45)cela vous donnera l'élément entier.

Savan Kaneriya
la source
4

Vous pouvez essayer Sugarjs sur http://sugarjs.com/ .

Il a une méthode très douce sur les tableaux, .find. Vous pouvez donc trouver un élément comme celui-ci:

array.find( {id: 75} );

Vous pouvez également lui passer un objet avec plus de propriétés pour ajouter une autre "clause where".

Notez que Sugarjs étend les objets natifs, et certaines personnes considèrent cela très mal ...

flammes profondes
la source
2
Eh bien, il est le mal, car il peut arriver que les nouvelles versions de ECMAScript peuvent introduire de nouvelles méthodes avec le même nom. Et devinez quoi, c'est exactement ce qui s'est passéfind . Ma suggestion est que si vous souhaitez étendre des prototypes natifs, utilisez toujours des noms plus spécifiques, en laissant les plus simples aux futurs développements standard.
MaxArt
ce commentaire a presque 2 ans et aujourd'hui je préfère quand même utiliser du lodash. Cependant, si vous le souhaitez, vous pouvez lire ce sujet sur le site Web de sugarjs. Ils prennent bonne position à votre avis: sugarjs.com/native
deepflame
1
L'opérateur a spécifiquement demandé une solution javascript ou jquery
Tobias Beuving
4

S'appuyant sur la réponse acceptée:

jQuery:

var foo = $.grep(myArray, function(e){ return e.id === foo_id})
myArray.pop(foo)

Ou CoffeeScript:

foo = $.grep myArray, (e) -> e.id == foo_id
myArray.pop foo
stevenspiel
la source
4

Récemment, je dois faire face à la même chose dans laquelle je dois rechercher la chaîne à partir d'un énorme tableau.

Après quelques recherches, j'ai trouvé que ce serait facile à manipuler avec un code simple:

Code:

var items = mydata.filter(function(item){
    return item.word.toLowerCase().startsWith( 'gk );
})

Voir https://jsfiddle.net/maheshwaghmare/cfx3p40v/4/

Serach de 20k cordes

maheshwaghmare
la source
3

Itérer sur n'importe quel élément du tableau. Pour chaque élément que vous visitez, vérifiez l'ID de cet élément. Si c'est un match, retournez-le.

Si vous voulez juste le codez:

function getId(array, id) {
    for (var i = 0, len = array.length; i < len; i++) {
        if (array[i].id === id) {
            return array[i];
        }
    }
    return null; // Nothing found
}

Et la même chose en utilisant les méthodes de tableau d'ECMAScript 5:

function getId(array, id) {
    var obj = array.filter(function (val) {
        return val.id === id;
    });

    // Filter returns an array, and we just want the matching item.
    return obj[0];
}
Zirak
la source
3

Tant que le navigateur prend en charge ECMA-262 , 5e édition (décembre 2009), cela devrait fonctionner, presque à une ligne:

var bFound = myArray.some(function (obj) {
    return obj.id === 45;
});
aggaton
la source
2
Presque. bFoundest juste un booléen truesi un élément satisfait la condition requise.
MaxArt
3

Vous pouvez le faire même en JavaScript pur en utilisant la fonction de "filtre" intégrée pour les tableaux:

Array.prototype.filterObjects = function(key, value) {
    return this.filter(function(x) { return x[key] === value; })
}

Alors maintenant, passez simplement "id" à la place de keyet "45" à la place de value, et vous obtiendrez l'objet complet correspondant à un id de 45. Ce serait donc,

myArr.filterObjects("id", "45");
kaizer1v
la source
16
Ne modifiez pas les objets que vous ne possédez pas.
Michał Perłakowski
3

Utilisez la Array.prototype.filter()fonction.

DÉMO : https://jsfiddle.net/sumitridhal/r0cz0w5o/4/

JSON

var jsonObj =[
 {
  "name": "Me",
  "info": {
   "age": "15",
   "favColor": "Green",
   "pets": true
  }
 },
 {
  "name": "Alex",
  "info": {
   "age": "16",
   "favColor": "orange",
   "pets": false
  }
 },
{
  "name": "Kyle",
  "info": {
   "age": "15",
   "favColor": "Blue",
   "pets": false
  }
 }
];

FILTRE

var getPerson = function(name){
    return jsonObj.filter(function(obj) {
      return obj.name === name;
    });
}
Sumit Ridhal
la source
comment puis-je rechercher dans un objet imbriqué? Comme les animaux domestiques = false devrait renvoyer deux objets.
Valay
utilisez la .filterméthode obj.infodans la boucle imbriquée. var getPerson = function(name){ return jsonObj.filter(function(obj) { return obj.info.filter(function(info) { return pets === false; }); }); }
Sumit Ridhal
vous pourriez aussi utiliser le style es6 imo ... const filterData = jsonObj.filter (obj => obj.name === 'Alex')
DagicCross
3

Nous pouvons utiliser les méthodes Jquery $.each()/$.grep()

var data= [];
$.each(array,function(i){if(n !== 5 && i > 4){data.push(item)}}

ou

var data = $.grep(array, function( n, i ) {
  return ( n !== 5 && i > 4 );
});

utilisez la syntaxe ES6:

Array.find, Array.filter, Array.forEach, Array.map

Ou utilisez Lodash https://lodash.com/docs/4.17.10#filter , Underscore https://underscorejs.org/#filter

TLbiz
la source
2

J'ai vraiment aimé la réponse fournie par Aaron Digulla mais je devais garder mon tableau d'objets afin de pouvoir le parcourir plus tard. Je l'ai donc modifié pour

	var indexer = {};
	for (var i = 0; i < array.length; i++) {
	    indexer[array[i].id] = parseInt(i);
	}
	
	//Then you can access object properties in your array using 
	array[indexer[id]].property

quincyaft
la source
Utilisé la même solution que la plus rapide pour trouver des éléments dans le tableau. Mais parseInt est redondant ici.
Aleha
1

Utilisation:

var retObj ={};
$.each(ArrayOfObjects, function (index, obj) {

        if (obj.id === '5') { // id.toString() if it is int

            retObj = obj;
            return false;
        }
    });
return retObj;

Il doit retourner un objet par id.

volumexxx
la source
vous pourriez raccourcir votre code en utilisant return obj.id === 5? obj: faux; J'utilise beaucoup $ .each pour itérer sur des tableaux.
marcel
@marcel: Cela ne fonctionnera pas. Comme renvoyer false mettra fin à la boucle, il ne trouvera l'objet que s'il était le premier élément du tableau.
Guffa
1

Cette solution peut également être utile:

Array.prototype.grep = function (key, value) {
    var that = this, ret = [];
    this.forEach(function (elem, index) {
        if (elem[key] === value) {
            ret.push(that[index]);
        }
    });
    return ret.length < 2 ? ret[0] : ret;
};
var bar = myArray.grep("id","45");

Je l'ai fait comme $.grepet si un objet est découvert, la fonction retournera l'objet, plutôt qu'un tableau.

soytian
la source
2
Ne modifiez pas les objets que vous ne possédez pas.
Michał Perłakowski
@Gothdo, je suis d'accord. Si quelqu'un ne le savait pas, il function will return the object, rather than an arraypourrait y avoir une erreur, mais je pense que cela dépend des utilisateurs.
soytian
0

A partir de la réponse de aggaton , ceci est une fonction qui renvoie en fait l'élément voulu (ou nullsi elle est introuvable), étant donné la arrayet une callbackfonction qui retourne une valeur de truthy pour l'élément « correct »:

function findElement(array, callback) {
    var elem;
    return array.some(function(e) {
        if (callback(e)) {
            elem = e;
            return true;
        }
    }) ? elem : null;
});

N'oubliez pas que cela ne fonctionne pas nativement sur IE8-, car il ne prend pas en charge some. Un polyfill peut être fourni, alternativement il y a toujours la forboucle classique :

function findElement(array, callback) {
    for (var i = 0; i < array.length; i++)
        if (callback(array[i])) return array[i];
    return null;
});

C'est en fait plus rapide et plus compact. Mais si vous ne voulez pas réinventer la roue, je suggère d'utiliser une bibliothèque d'utilitaires comme le soulignement ou le lodash.

MaxArt
la source
0

Le plus court,

var theAnswerObj = _.findWhere(array, {id : 42});
Manu
la source
1
Cela nécessite l'utilisation de la bibliothèque de soulignement, l'OP a demandé une solution javascript ou jQuery
standard
2
une fois que vous incluez le trait de soulignement, ce n'est pas une réponse courte!
Tim Ogilvy
-1

Considérez "axesOptions" comme un tableau d'objets avec un format d'objet étant {: field_type => 2,: fields => [1,3,4]}

function getFieldOptions(axesOptions,choice){
  var fields=[]
  axesOptions.each(function(item){
    if(item.field_type == choice)
        fields= hashToArray(item.fields)
  });
  return fields;
}
ramya
la source