méthode indexOf dans un tableau d'objets?
Quelle est la meilleure méthode pour obtenir l'index d'un tableau contenant des objets?
Imaginez ce scénario:
var hello = {
hello: 'world',
foo: 'bar'
};
var qaz = {
hello: 'stevie',
foo: 'baz'
}
var myArray = [];
myArray.push(hello,qaz);
Maintenant, je voudrais avoir l' indexOf
l'objet qui hello
la propriété est 'stevie'
, qui, dans cet exemple, serait 1
.
Je suis assez débutant avec JavaScript et je ne sais pas s'il existe une méthode simple ou si je devrais construire ma propre fonction pour le faire.
27 réponses
Je pense que vous pouvez le résoudre en une seule ligne en utilisant la fonction map :
pos = myArray.map(function(e) { return e.hello; }).indexOf('stevie');
Tableau.prototype.findIndex est pris en charge dans tous les navigateurs autres que IE (non-edge). Mais le polyfill fourni est agréable.
var indexOfStevie = myArray.findIndex(i => i.hello === "stevie");
La solution avec map est correcte. Mais vous parcourez le tableau entier à chaque recherche. Ce n'est que le pire des cas pour findIndex qui arrête l'itération une fois qu'une correspondance est trouvée.
var searchTerm = "stevie",
index = -1;
for(var i = 0, len = myArray.length; i < len; i++) {
if (myArray[i].hello === searchTerm) {
index = i;
break;
}
}
, Ou en fonction:
function arrayObjectIndexOf(myArray, searchTerm, property) {
for(var i = 0, len = myArray.length; i < len; i++) {
if (myArray[i][property] === searchTerm) return i;
}
return -1;
}
arrayObjectIndexOf(arr, "stevie", "hello"); // 1
Juste quelques remarques:
- ne pas utiliser for...in boucles sur les tableaux
- assurez-vous de sortir de la boucle ou de retour de la fonction une fois que vous avez trouvé votre "aiguille"
- soyez prudent avec l'égalité des objets
Par exemple
var a = {obj: 0};
var b = [a];
b.indexOf({obj: 0}); // -1 not found
Dans ES2015, c'est assez facile:
myArray.map(x => x.hello).indexOf('stevie')
Ou, probablement avec de meilleures performances pour les tableaux plus grands:
myArray.findIndex(x => x.hello === 'stevie')
var idx = myArray.reduce( function( cur, val, index ){
if( val.hello === "stevie" && cur === -1 ) {
return index;
}
return cur;
}, -1 );
J'aime la réponse de Pablo, mais Array # indexOf et Array # map ne fonctionnent pas sur tous les navigateurs. Underscore utilisera du code natif s'il est disponible, mais a également des solutions de repli. De plus, il a la méthode pluck pour faire exactement ce que fait la méthode de carte anonyme de Pablo.
var idx = _.chain(myArray).pluck("hello").indexOf("Stevie").value();
Ou prototype:
Array.prototype.indexOfObject = function arrayObjectIndexOf(property, value) {
for (var i = 0, len = this.length; i < len; i++) {
if (this[i][property] === value) return i;
}
return -1;
}
myArr.indexOfObject("name", "stevie");
Bref
myArray.indexOf('stevie','hello')
Cas D'Utilisation:
/*****NORMAL****/
[2,4,5].indexOf(4) ;//OUTPUT 1
/****COMPLEX*****/
[{slm:2},{slm:4},{slm:5}].indexOf(4,'slm');//OUTPUT 1
//OR
[{slm:2},{slm:4},{slm:5}].indexOf(4,function(e,i){
return e.slm;
});//OUTPUT 1
/***MORE Complex**/
[{slm:{salat:2}},{slm:{salat:4}},{slm:{salat:5}}].indexOf(4,function(e,i){
return e.slm.salat;
});//OUTPUT 1
API:
Array.prototype.indexOfOld=Array.prototype.indexOf
Array.prototype.indexOf=function(e,fn){
if(!fn){return this.indexOfOld(e)}
else{
if(typeof fn ==='string'){var att=fn;fn=function(e){return e[att];}}
return this.map(fn).indexOfOld(e);
}
};
array.filter(function(item, indx, arr){ return(item.hello === 'stevie'); })[0];
Attention au [0]
.
Il est correct d'utiliser reduce
comme dans la réponse de Antonio Laguna
.
Toutes mes excuses pour la brièveté...
J'ai fait quelques tests de performance de diverses réponses ici, que n'importe qui peut les exécuter soi-même:
Https://jsperf.com/find-index-of-object-in-array-by-contents
Sur la base de mes tests initiaux dans Chrome, la méthode suivante (en utilisant une boucle for configurée dans un prototype) est la plus rapide:
Array.prototype.indexOfObject = function (property, value) {
for (var i = 0, len = this.length; i < len; i++) {
if (this[i][property] === value) return i;
}
return -1;
}
myArray.indexOfObject("hello", "stevie");
Ce code est une version légèrement modifiée de la réponse de Nathan Zaetta.
Dans les benchmarks de performance, Je l'ai essayé avec à la fois la cible étant au milieu (index 500) et très fin (index 999) d'un tableau d'objets 1000, et même si je mets la cible en tant que dernier élément du tableau (ce qui signifie qu'il doit parcourir chaque élément du tableau avant qu'il ne soit trouvé), il finit toujours le plus rapide.
Cette solution a également l'avantage d'être l'une des plus laconiques pour l'exécution répétée, puisque seule la dernière ligne doit être répétée:
myArray.indexOfObject("hello", "stevie");
Simple:
myArray.indexOf(myArray.filter(function(item) {
return item.hello == "stevie"
})[0])
Si vous êtes seulement intéressé à trouver le poste, consultez la réponse de @Pablo .
pos = myArray.map(function(e) { return e.hello; }).indexOf('stevie');
Cependant, si vous êtes impatient de trouver l'élément (c'est-à-dire si vous envisagez de faire quelque chose comme ça myArray[pos]
), il existe un moyen plus efficace de le faire en utilisantfilter
.
element = myArray.filter((e) => e.hello === 'stevie')[0];
Voir les résultats de performance (~+42% ops / sec): http://jsbench.github.io/#7fa01f89a5dc5cc3bee79abfde80cdb3
J'ai comparé plusieurs méthodes et j'ai reçu un résultat avec le moyen le plus rapide de résoudre ce problème. C'est une boucle for
. C'est 5 fois plus rapide que toute autre méthode.
Voici la page du test: https://jsbench.me/9hjewv6a98
Voir cet exemple: http://jsfiddle.net/89C54/
for (i = 0; i < myArray.length; i++) {
if (myArray[i].hello === 'stevie') {
alert('position: ' + i);
return;
}
}
Il commence à compter avec zéro.
J'ai fait une fonction générique pour vérifier que ci-dessous est le code et fonctionne pour n'importe quel objet
function indexOfExt(list, item) {
var len = list.length;
for (var i = 0; i < len; i++) {
var keys = Object.keys(list[i]);
var flg = true;
for (var j = 0; j < keys.length; j++) {
var value = list[i][keys[j]];
if (item[keys[j]] !== value) {
flg = false;
}
}
if (flg == true) {
return i;
}
}
return -1;
}
var items = [{ "hello": 'world', "foo": 'bar' }];
var selectedItem = { "hello": 'world', "foo": 'bar' };
alert(items.indexOf(selectedItem));
alert(indexOfExt(items, selectedItem));
La première alerte retournera -1 (signifie match introuvable) et la deuxième alerte retournera 0 (signifie match trouvé).
Utiliser _.findIndex
à partir de trait de soulignement.bibliothèque js
Voici l'exemple
_.findIndex([{a:1},{a: 2,c:10},{a: 3}], {a:2,c:10}) //1
Essayez ceci:
console.log(Object.keys({foo:"_0_", bar:"_1_"}).indexOf("bar"));
Https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
Vous pouvez utiliser une fonction native et pratique Array.prototype.findIndex()
fondamentalement:
La méthode findIndex () renvoie un index dans le tableau, si un élément du tableau satisfait la fonction de test fournie. Sinon, -1 est retourné.
Juste une note, il n'est pas pris en charge sur Internet Explorer, Opera et Safari, mais vous pouvez utiliser un Polyfill fourni dans le lien ci-dessous.
Plus informations:
Https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex
var hello = {
hello: 'world',
foo: 'bar'
};
var qaz = {
hello: 'stevie',
foo: 'baz'
}
var myArray = [];
myArray.push(hello, qaz);
var index = myArray.findIndex(function(element, index, array) {
if (element.hello === 'stevie') {
return true;
}
});
alert('stevie is at index: ' + index);
Plus loin de @Monika Garg réponse , Vous pouvez utiliser findIndex()
(Il y a un polyfill pour les navigateurs non supprimés).
J'ai vu que les gens ont rejeté cette réponse, et j'espère qu'ils l'ont fait à cause de la mauvaise syntaxe, car à mon avis, c'est la façon la plus élégante.
La méthode findIndex () renvoie un index dans le tableau, si un élément du tableau satisfait la fonction de test fournie. Sinon, -1 est retourné.
Par exemple:
var hello = {
hello: 'world',
foo: 'bar'
};
var qaz = {
hello: 'stevie',
foo: 'baz'
}
var myArray = [];
myArray.push(hello,qaz);
var index = myArray.findIndex(function(element) {
return element.hello == 'stevie';
});
alert(index);
C'est la façon de trouver l'objet de l'indice dans le tableau
var myArray = [{ hello: 'world',
foo: 'bar'
},{
hello: 'stevie',
foo: 'baz'
}];
for (i = 0; i < myArray.length; i++) {
if (myArray[i].hello === 'stevie') {
alert('position: ' + i);
return;
}
}
Utilisation de L'ES6 findIndex
Méthode , sans lodash ou toute autre bibliothèque, vous pouvez écrire:
function deepIndexOf(arr, obj) {
return arr.findIndex(function (cur) {
return Object.keys(obj).every(function (key) {
return obj[key] === cur[key];
});
});
}
Cela comparera les propriétés immédiates de l'objet, mais pas les récursivité dans les propriétés.
Si votre implémentation ne fournit pas encore findIndex
(la plupart ne le font pas), vous pouvez ajouter un polyfill léger qui prend en charge cette recherche:
function deepIndexOf(arr, obj) {
function findIndex = Array.prototype.findIndex || function (pred) {
for (let i = 0; i < this.length; ++i) {
if (pred.call(this, this[i], i)) {
return i;
}
}
return -1;
}
return findIndex.call(arr, function (cur) {
return Object.keys(obj).every(function (key) {
return obj[key] === cur[key];
});
});
}
(dans ma réponse sur cette dupe)
Si votre objet est le même objet que celui que vous utilisez dans le tableau, vous devriez pouvoir obtenir l'index de l'objet de la même manière que si c'était une chaîne.
var hello = {
hello: 'world',
foo: 'bar'
};
var qaz = {
hello: 'stevie',
foo: 'baz'
}
var qazCLONE = { // new object instance and same structure
hello: 'stevie',
foo: 'baz'
}
var myArray = [hello,qaz];
myArray.indexOf(qaz) // should return 1
myArray.indexOf(qazCLONE) // should return -1
Alors que, la plupart des autres réponses ici sont valides. Parfois, il est préférable de simplement faire une courte FONCTION simple près de l'endroit où vous l'utiliserez.
// indexOf wrapper for the list of objects
function indexOfbyKey(obj_list, key, value) {
for (index in obj_list) {
if (obj_list[index][key] === value) return index;
}
return -1;
}
// Find the string in the list (default -1)
var test1 = indexOfbyKey(object_list, 'name', 'Stevie');
var test2 = indexOfbyKey(object_list, 'last_name', 'some other name');
Cela dépend de ce qui est important pour vous. Il pourrait sauver des lignes de code et être très intelligent d'utiliser un one-liner, ou de mettre une solution générique quelque part qui couvre divers cas de bord. Mais parfois, il vaut mieux simplement dire: "ici, je l'ai fait comme ça" plutôt que de laisser les futurs développeurs avoir un travail d'ingénierie inverse supplémentaire. Surtout si vous considérez - vous comme "un débutant" comme dans votre question.
, Vous pouvez simplement utiliser
const someId = 2;
const array = [{id:1}, {id:2}, {id:3}];
const index = array.reduce((i, item, index) => item.id === someId ? index : i, -1);
alert('someId ' + someId + ' is at index ' + index);
Pas de soulignement, pas pour, juste une réduction.
var hello = {hello: "world", foo: "bar"};
var qaz = {hello: "stevie", foo: "baz"};
var myArray = [];
myArray.push(hello,qaz);
function indexOfObject( arr, key, value ) {
var j = -1;
var result = arr.some(function(obj, i) {
j++;
return obj[key] == value;
})
if (!result) {
return -1;
} else {
return j;
};
}
alert(indexOfObject(myArray,"hello","world"));
, Vous pouvez créer votre propre prototype pour ce faire:
Quelque Chose comme:
Array.prototype.indexOfObject = function (object) {
for (var i = 0; i < this.length; i++) {
if (JSON.stringify(this[i]) === JSON.stringify(object))
return i;
}
}
Cela fonctionne sans code personnalisé
var arr, a, found;
arr = [{x: 1, y: 2}];
a = {x: 1, y: 2};
found = JSON.stringify(arr).indexOf(JSON.stringify(a)) > - 1;
// found === true
Note: cela ne donne pas l'index réel, il indique seulement si votre objet existe dans la structure de données actuelle
Je préfère utiliser findIndex()
méthode:
var index = myArray.findIndex('hello','stevie');
index
vous donnera le numéro d'index.