Comment obtenir l'index d'un objet par sa propriété en JavaScript?

241

Par exemple, j'ai:

var Data = [
  { id_list: 1, name: 'Nick', token: '312312' },
  { id_list: 2, name: 'John', token: '123123' },
]

Ensuite, je veux trier / inverser cet objet par nameexemple. Et puis je veux obtenir quelque chose comme ça:

var Data = [
  { id_list: 2, name: 'John', token: '123123' },
  { id_list: 1, name: 'Nick', token: '312312' },
]

Et maintenant, je veux connaître l'index de l'objet avec propriété name='John'pour obtenir la valeur du jeton de propriété.

Comment puis-je résoudre le problème?

rsboarder
la source
Pourquoi voulez-vous d'abord trier la liste avant de rechercher la propriété?
JJJ
Les objets JavaScript sont {Key:Value}, je l'ai corrigé pour vous.
Rocket Hazmat
doublon possible du tableau JSON
2012
Si vous parcourez les réponses, il semble qu'il y ait un Dataobjet natif . Il s'agit simplement d'un nom de variable en majuscule, ce qui est contraire à la convention. Si quelqu'un d'autre est gêné par cela, je modifierai la question et les réponses pour corriger cette dénomination.
Roy Prins
Question connexe: stackoverflow.com/questions/10557486/…
Anton Tarasenko

Réponses:

170

Comme les autres réponses le suggèrent, faire une boucle à travers le tableau est probablement le meilleur moyen. Mais je le mettrais dans sa propre fonction, et le rendrais un peu plus abstrait:

function findWithAttr(array, attr, value) {
    for(var i = 0; i < array.length; i += 1) {
        if(array[i][attr] === value) {
            return i;
        }
    }
    return -1;
}

var Data = [
    {id_list: 2, name: 'John', token: '123123'},
    {id_list: 1, name: 'Nick', token: '312312'}
];

Avec cela, vous pouvez non seulement trouver celui qui contient 'John', mais vous pouvez également trouver celui qui contient le jeton '312312':

findWithAttr(Data, 'name', 'John'); // returns 0
findWithAttr(Data, 'token', '312312'); // returns 1
findWithAttr(Data, 'id_list', '10'); // returns -1

EDIT: fonction mise à jour pour retourner -1 lorsqu'elle n'est pas trouvée, elle suit donc la même construction que Array.prototype.indexOf ()

Chris Pickett
la source
1
Ajout d'une réponse étendant cela pour couvrir la recherche plus profonde qu'un niveau d'attribut. Merci pour cela Chris - a vraiment aidé: D
Ed Shee
3
Pour ceux qui auront des problèmes avec cette solution, n'oubliez pas que le signe égal === vérifiera non seulement la valeur mais aussi le type de données. ainsi, la comparaison de la date, des nombres et des valeurs vides peut retourner false si la valeur réelle est une chaîne. Vous pouvez utiliser == signe égal si le type de données n'est pas essentiel pour vous.
David Addoteye
NE FAITES PAS CELA. Apprenez à utiliser des fonctions d'ordre supérieur, c'est l'ancienne façon de faire les choses.
Led
327

Depuis la partie de tri est déjà répondu. Je vais juste proposer une autre façon élégante d'obtenir l'indexOf d'une propriété dans votre tableau

Votre exemple est:

var Data = [
    {id_list:1, name:'Nick',token:'312312'},
    {id_list:2,name:'John',token:'123123'}
]

Tu peux faire:

var index = Data.map(function(e) { return e.name; }).indexOf('Nick');

Array.prototype.mapn'est pas disponible sur IE7 ou IE8. Compatibilité ES5

Et le voici avec ES6 et la syntaxe des flèches, ce qui est encore plus simple:

const index = Data.map(e => e.name).indexOf('Nick');
Allemand Attanasio
la source
4
Je dois répéter le tableau entier, quoi qu'il arrive. La première méthode n'en a pas besoin.
German Attanasio
1
Simple, mais prenez en compte les performances lors de l'utilisation de grands ensembles de données
gavioto
1
Une très bonne réponse m'a aidé à résoudre ce problème!
NiallMitch14
1
Cette solution est charmante. Puissiez-vous vivre jusqu'à mille ans, monsieur.
deepelement
3
Faire une carte puis indexOf dans la version ES6 signifie qu'ils vont boucler deux fois sur le tableau. Au lieu de cela, vous devez utiliser la méthode findIndex indiquée dans ma réponse
silverlight513
209

Si vous êtes d'accord avec l'utilisation d'ES6. Les tableaux ont désormais la fonction findIndex . Ce qui signifie que vous pouvez faire quelque chose comme ça:

const index = Data.findIndex(item => item.name === 'John');
silverlight513
la source
6
de loin la solution la plus directe et élégante, je ferais un petit pas que findIndex est gourmand - dans mon cas, c'était parfait - mais les utilisateurs doivent savoir que si vous avez des objets avec des valeurs en double (c'est-à-dire deux objets avec name: John) cela ne retournera que le premier match
GrayedFox
Impressionnant!! Je vous remercie.
moreirapontocom
@GrayedFox ne voulais-tu pas dire PAS gourmand? Gourmand signifie plus de résultats et findIndex ne renvoie que la première correspondance.
Jos
1
Désolé @Jos mais je pense que vous ne comprenez pas très bien ce que fait un algorithme de recherche gourmand . Un algorithme gourmand ne prend en compte que les informations dont il dispose, ce qui est efficace en termes de calcul, par exemple pour rechercher un élément dans une liste lorsque vous n'avez besoin que d'un seul résultat. La méthode findIndex est gourmande précisément car elle ne renvoie que la première correspondance. Si ce n'était pas gourmand, il continuerait à chercher. Vous pensez au terme "gourmand" tel qu'il est utilisé dans l'anglais au quotidien, mais dans le contexte de la programmation (c'est-à-dire SO), c'est le contraire de ce que vous pensez;)
GrayedFox
Merci d'avoir expliqué @GrayedFox. Ma référence aux gourmands provenait en fait aussi de la programmation mais liée aux expressions régulières où les gourmands prennent plus de caractères que les non gourmands! :-)
Jos
28
var index = Data.findIndex(item => item.name == "John")

Qui est une version simplifiée de:

var index = Data.findIndex(function(item){ return item.name == "John"})

De mozilla.org:

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

edank
la source
2
Utilisez "===" pour comparer les chaînes, c'est la seule chose qui manque dans cette réponse.
Bruno Tavares
@BrunoTavares, quel scénario pensez-vous serait différent dans ce cas?
edank
1
@edank Si OP devait vérifier le tokenchamp au lieu du namechamp, il pourrait y avoir des problèmes, comme Data[0].token == 312312évalue à true, mais Data[0].token === 321321évalue à false.
kem
@edank jetez un oeil dans cette réponse stackoverflow.com/questions/359494/…
Bruno Tavares
23

Si vous rencontrez des problèmes avec IE, vous pouvez utiliser la fonction map () qui est prise en charge à partir de la version 9.0:

var index = Data.map(item => item.name).indexOf("Nick");
Alain T.
la source
1
La réponse ci-dessous fournit plus d'informations et a été publiée en premier.
Alexander
C'est certainement la meilleure solution pour cela.
Bebolicious
4

Le seul moyen connu pour moi est de parcourir tous les tableaux:

var index=-1;
for(var i=0;i<Data.length;i++)
  if(Data[i].name==="John"){index=i;break;}

ou insensible à la casse:

var index=-1;
for(var i=0;i<Data.length;i++)
  if(Data[i].name.toLowerCase()==="john"){index=i;break;}

Sur le résultat, la variable index contient l'index de l'objet ou -1 s'il n'est pas trouvé.

Andrew D.
la source
2

une manière prototypique

(function(){
  if (!Array.prototype.indexOfPropertyValue){
    Array.prototype.indexOfPropertyValue = function(prop,value){
      for (var index = 0; index < this.length; index++){
        if (this[index][prop]){
          if (this[index][prop] == value){
            return index;
          }
        }
      }
      return -1;
    }
  }
 })();
 // usage:
 var Data = [
 {id_list:1, name:'Nick',token:'312312'},{id_list:2,name:'John',token:'123123'}];
 Data.indexOfPropertyValue('name','John'); // returns 1 (index of array);
 Data.indexOfPropertyValue('name','Invalid name') // returns -1 (no result);
 var indexOfArray = Data.indexOfPropertyValue('name','John');
 Data[indexOfArray] // returns desired object.
Patrik Wallin
la source
J'ai dû changer cela un peu pour travailler dans ma situation - je cherchais l'index d'une propriété avec une valeur nulle et la cinquième ligne faisait que cela sautait cet index.
David Brunow
1

Vous pouvez utiliser Array.sort en utilisant une fonction personnalisée comme paramètre pour définir votre mécanisme de tri.

Dans votre exemple, cela donnerait:

var Data = [
    {id_list:1, name:'Nick',token:'312312'},{id_list:2,name:'John',token:'123123'}
]

Data.sort(function(a, b){
    return a.name < b.name ? -1 : a.name > b.name ? 1 : 0;
});

alert("First name is : " + Data[0].name); // alerts 'John'
alert("Second name is : " + Data[1].name); // alerts 'Nick'

La fonction de tri doit retourner soit -1 si a doit venir avant b, 1 si a doit venir après b et 0 si les deux sont égaux. C'est à vous de définir la bonne logique dans votre fonction de tri pour trier le tableau.

Edit: Vous avez manqué la dernière partie de votre question où vous voulez connaître l'index. Vous devrez parcourir le tableau pour trouver cela comme d'autres l'ont dit.


la source
1

Parcourez simplement votre tableau et trouvez la position:

var i = 0;
for(var item in Data) {
    if(Data[item].name == 'John')
        break;
    i++;
}
alert(i);
Sascha Galley
la source
Cela devrait être if(Data[item].name == 'John'), je l'ai réparé pour vous.
Rocket Hazmat
Cela a un moment. Si « non trouvé » variable i contiens indice positif. Et pour tester 'non trouvé', il faut comparer si i === Data.length
Andrew D.
Le deuxième moment est si le tableau contient des propriétés personnalisées non indexées. Par exemple: var Data [1,2,3,4,5]; Données ["test"] = 7897; Comparer la sortie de: for (var i in Data) alert (Data [i]); et pour (var i = 0; i <Data.length; i ++) alert (Data [i]);
Andrew D.24
1

Pourquoi n'utilisez-vous pas une petite solution de contournement?

Créez un nouveau tableau avec des noms comme index. après cela, toutes les recherches utiliseront des index. Donc, une seule boucle. Après cela, vous n'avez pas besoin de parcourir tous les éléments!

var Data = [
    {id_list:1, name:'Nick',token:'312312'},{id_list:2,name:'John',token:'123123'}
    ]
var searchArr = []
Data.forEach(function(one){
  searchArr[one.name]=one;
})
console.log(searchArr['Nick'])

http://jsbin.com/xibala/1/edit

exemple en direct.


la source
Cela signifie que vous devez d'abord tout boucler ... puis modifier les objets (à moins que vous ne les cloniez, mais c'est encore plus de surcharge). Et après cela, vous bouclez à nouveau (partiellement au moins).
Jos
1

Extension de la réponse de Chris Pickett parce que dans mon cas, je devais rechercher plus profondément qu'un niveau d'attribut:

function findWithAttr(array, attr, value) {
  if (attr.indexOf('.') >= 0) {
    var split = attr.split('.');
    var attr1 = split[0];
    var attr2 = split[1];
    for(var i = 0; i < array.length; i += 1) {
      if(array[i][attr1][attr2] === value) {
        return i;
      }
    }
  } else {
    for(var i = 0; i < array.length; i += 1) {
      if(array[i][attr] === value) {
        return i;
      }
    }
  };
};

Vous pouvez passer 'attr1.attr2' dans la fonction

Ed Shee
la source
1

Et ça ? :

Data.indexOf(_.find(Data, function(element) {
  return element.name === 'John';
}));

En supposant que vous utilisez lodash ou underscorejs.

Ellone
la source
1
var fields = {
teste:
{
    Acess:
    {
        Edit: true,
      View: false

      }
 },
teste1:
{
    Acess:
    {
        Edit: false,
      View: false

      }
  }
};

console.log(find(fields,'teste'));
function find(fields,field){
    for(key in fields){
        if(key == field){
        return true;
    }
}
return false;
}

Si vous avez un objet avec plusieurs objets à l'intérieur, si vous voulez savoir si certains objets sont inclus sur l'objet maître, mettez simplement find (MasterObject, 'Object to Search'), cette fonction retournera la réponse si elle existe ou non (TRUE ou FALSE ), J'espère de l'aide avec cela, peut voir l'exemple sur JSFiddle .

Pedro Monteiro Arantes
la source
Ajoutez quelques explications avec la réponse pour savoir comment cette réponse aide OP à résoudre le problème actuel
ρяσѕρєя K
@ ρяσѕρєяK, Merci pour votre suggestion, j'ai déjà ajouté l'explication :)
Pedro Monteiro Arantes
1
let indexOf = -1;
let theProperty = "value"
let searchFor = "something";

theArray.every(function (element, index) {

    if (element[theProperty] === searchFor) {
        indexOf = index;
        return false;
    }
    return true;
});
Itay Merchav
la source
1
collection.findIndex(item => item.value === 'smth') !== -1
Eugene Lyzo
la source
Bien que cet extrait de code puisse résoudre la question, y compris une explication aide vraiment à améliorer la qualité de votre message. N'oubliez pas que vous répondrez à la question pour les lecteurs à l'avenir, et ces personnes pourraient ne pas connaître les raisons de votre suggestion de code. Essayez également de ne pas surcharger votre code avec des commentaires explicatifs, car cela réduit la lisibilité du code et des explications!
Au revoir StackExchange
1

Si vous souhaitez obtenir la valeur du jeton de propriété, vous pouvez également essayer ceci

    let data=[
      { id_list: 1, name: 'Nick', token: '312312' },
      { id_list: 2, name: 'John', token: '123123' },
    ]

    let resultingToken =  data[_.findKey(data,['name','John'])].token

où _.findKey est la fonction d'un lodash

Akash Singh
la source
0

Alternativement à la réponse de German Attanasio Ruiz, vous pouvez éliminer la 2ème boucle en utilisant Array.reduce () au lieu de Array.map ();

var Data = [
    { name: 'hypno7oad' }
]
var indexOfTarget = Data.reduce(function (indexOfTarget, element, currentIndex) {
    return (element.name === 'hypno7oad') ? currentIndex : indexOfTarget;
}, -1);
hypno7oad
la source
-1

Utilisation du trait de soulignement:

var index = _.indexOf(_.pluck(item , 'name'), 'Nick');
M Faisal Hameed
la source