web-dev-qa-db-fra.com

Comment déterminer si un tableau Javascript contient un objet avec un attribut égal à une valeur donnée?

J'ai un tableau comme

vendors = [
    {
      Name: 'Magenic',
      ID: 'ABC'
     },
    {
      Name: 'Microsoft',
      ID: 'DEF'
    } and so on... 
];

Comment vérifier ce tableau pour voir si Magenic existe? Je ne veux pas faire de boucle, à moins d'y être obligé. Je travaille avec potentiellement quelques milliers de disques.

MIS À JOUR

Comme cela a été un post populaire, j'ai pensé partager quelque chose de nouveau que j'ai trouvé. Et il semble que @CAFxX l’ait déjà partagé! Je devrais les lire plus souvent. Je suis tombé sur https://benfrain.com/understanding-native-javascript-array-methods/ .

vendors.filter(function(vendor){ return vendor.Name === "Magenic" });

Et avec ECMAScript 2015, l'utilisation des nouvelles fonctions de flèche est encore plus simple:

vendors.filter(vendor => (vendor.Name === "Magenic"));
363
David Lozzi

2018 edit: cette réponse date de 2011, avant que les navigateurs ne prennent largement en charge les méthodes de filtrage par tableaux et les fonctions de flèche. Jetez un coup d'œil à La réponse de CAFxX .

Il n'y a pas de moyen "magique" de vérifier quelque chose dans un tableau sans boucle. Même si vous utilisez une fonction, la fonction elle-même utilisera une boucle. Ce que vous pouvez faire est de sortir de la boucle dès que vous trouvez ce que vous cherchez pour réduire le temps de calcul.

var found = false;
for(var i = 0; i < vendors.length; i++) {
    if (vendors[i].Name == 'Magenic') {
        found = true;
        break;
    }
}
195
Alex Turpin

Pas besoin de réinventer le roue boucle, du moins pas explicitement (avec fonctions de flèche , navigateurs modernes uniquement ):

if (vendors.filter(e => e.name === 'Magenic').length > 0) {
  /* vendors contains the element we're looking for */
}

ou mieux encore:

if (vendors.some(e => e.name === 'Magenic')) {
  /* vendors contains the element we're looking for */
}

EDIT: Si vous avez besoin de compatibilité avec les mauvais navigateurs, votre meilleur pari est:

if (vendors.filter(function(e) { return e.name === 'Magenic'; }).length > 0) {
  /* vendors contains the element we're looking for */
}
524
CAFxX

Aucune boucle nécessaire. Trois méthodes qui me viennent à l’esprit:

Array.prototype.some ()

C’est la réponse la plus exacte à votre question, c’est-à-dire "vérifier si quelque chose existe", ce qui implique un résultat boolé. Cela sera vrai s'il y a des objets 'Magenic', faux sinon:

let hasMagenicVendor = vendors.some( vendor => vendor['Name'] === 'Magenic' )

Array.prototype.filter ()

Cela retournera un tableau de tous les objets 'Magenic', même s'il n'y en a qu'un (retournera un tableau d'un élément):

let magenicVendors = vendors.filter( vendor => vendor['Name'] === 'Magenic' )

Si vous essayez de contraindre cela à un booléen, cela ne fonctionnera pas, car un tableau vide (pas d'objets 'Magenic') est toujours la vérité. Donc, utilisez simplement magenicVendors.length dans votre conditionnel.

Array.prototype.find ()

Cela retournera le premier objet 'Magenic' (ou undefined s'il n'y en a pas):

let magenicVendor = vendors.find( vendor => vendor['Name'] === 'Magenic' );

Ceci oblige à un booléen correct (tout objet est la vérité, undefined est la fausseté).


Remarque: J'utilise fournisseur ["Nom"] au lieu de fournisseur.Nom en raison de l'étrange casse des noms de propriété.

Remarque 2: Aucune raison d'utiliser l'égalité en vrac (==) au lieu d'une égalité stricte (===) lors de la vérification du nom.

43
boxtrain

La réponse acceptée fonctionne toujours, mais nous avons maintenant une méthode native ECMAScript 6 [Array.find][1] pour obtenir le même effet. 

Citant MDN:

La méthode find () renvoie la valeur du premier élément du tableau qui satisfait à la fonction de test fournie. Sinon, non défini est revenu.

var arr = []; 
var item = {
  id: '21',
  step: 'step2',
  label: 'Banana',
  price: '19$'
};

arr.Push(item);
/* note : data is the actual object that matched search criteria 
  or undefined if nothing matched */
var data = arr.find( function( ele ) { 
    return ele.id === '21';
} );

if( data ) {
 console.log( 'found' );
 console.log(data); // This is entire object i.e. `item` not boolean
}

Voir mon lien jsfiddle Il existe un polyfill pour IE fourni par mozilla

39
TeaCoder

À moins que vous ne vouliez le restructurer comme ceci:

vendors = {
    Magenic: {
      Name: 'Magenic',
      ID: 'ABC'
     },
    Microsoft: {
      Name: 'Microsoft',
      ID: 'DEF'
    } and so on... 
};

auquel vous pouvez faire if(vendors.Magnetic)

Vous devrez faire une boucle

16
Keith.Abramo

Vous ne pouvez pas sans regarder vraiment dans l'objet.

Vous devriez probablement changer un peu votre structure, comme

vendors = {
    Magenic:   'ABC',
    Microsoft: 'DEF'
};

Ensuite, vous pouvez simplement l'utiliser comme une recherche.

vendors['Microsoft']; // 'DEF'
vendors['Apple']; // undefined
13
jAndy

Comme le PO a posé la question si la clé existe ou non

Une solution plus élégante qui rendra booléen en utilisant la fonction de réduction ES6 peut être

const magenicVendorExists =  vendors.reduce(vendor => (vendor.Name === "Magenic"), false);

Remarque: Le paramètre initial de reduction est false et si le tableau a la clé, il retournera la valeur true.

J'espère que cela aidera à une implémentation de code meilleure et plus propre

9
Jay Chakra

Voici comment je le ferais

const found = vendors.some(item => item.Name === 'Magenic');

La méthode array.some() vérifie s'il existe au moins une valeur dans un tableau qui correspond aux critères et renvoie un booléen. A partir de là, vous pouvez aller avec:

if (found) {
// do something
} else {
// do something else
}
9
Mirza Leka

Vous devez faire une boucle, il n'y a pas moyen de le contourner.

function seekVendor(vendors, name) {
  for (var i=0, l=vendors.length; i<l; i++) {
    if (typeof vendors[i] == "object" && vendors[i].Name === name) {
      return vendors[i];
    }
  }
}

Bien sûr, vous pouvez utiliser une bibliothèque comme linq.js pour rendre cela plus agréable:

Enumerable.From(vendors).Where("$.Name == 'Magenic'").First();

(voir jsFiddle pour une démo)

Je doute que linq.js soit plus rapide qu'une boucle simple, mais il est certainement plus flexible lorsque les choses deviennent un peu plus compliquées.

4
Tomalak

si vous utilisez jquery, vous pouvez tirer parti de grep pour créer un tableau avec tous les objets correspondants:

var results = $.grep(vendors, function (e) {
    return e.Name == "Magenic";
});

puis utilisez le tableau de résultats:

for (var i=0, l=results.length; i<l; i++) {
    console.log(results[i].ID);
}
4
Ethan

Corrigez-moi si je me trompe ... j'aurais pu utiliser la méthode forEach comme celle-ci,

var found=false;
vendors.forEach(function(item){
   if(item.name === "name"){
       found=true;
       return;
   }
});

De nos jours, je suis habitué à cela, à cause de sa simplicité et de son caractère explicite Word ..__ Merci.

1
Siddhesh Mishra

Pour comparer un objet à un autre, je combine une boucle for in (utilisée pour parcourir des objets) et un peu () . Vous n'avez pas à vous soucier d'un tableau qui sort des limites, etc., de manière à enregistrer du code. La documentation sur .some peut être trouvée ici

var productList = [{id: 'text3'}, {id: 'text2'}, {id: 'text4', product: 'Shampoo'}]; // Example of selected products
var theDatabaseList = [{id: 'text1'}, {id: 'text2'},{id: 'text3'},{id:'text4', product: 'shampoo'}];    
var  objectsFound = [];

for(let objectNumber in productList){
    var currentId = productList[objectNumber].id;   
    if (theDatabaseList.some(obj => obj.id === currentId)) {
        // Do what you need to do with the matching value here
        objectsFound.Push(currentId);
    }
}
console.log(objectsFound);

Une autre manière de comparer un objet à un autre consiste à utiliser une boucle for imbriquée avec Object.keys (). Length pour obtenir la quantité d'objets dans le tableau. Code ci-dessous:

var productList = [{id: 'text3'}, {id: 'text2'}, {id: 'text4', product: 'Shampoo'}]; // Example of selected products
var theDatabaseList = [{id: 'text1'}, {id: 'text2'},{id: 'text3'},{id:'text4', product: 'shampoo'}];    
var objectsFound = [];

for(var i = 0; i < Object.keys(productList).length; i++){
        for(var j = 0; j < Object.keys(theDatabaseList).length; j++){
        if(productList[i].id === theDatabaseList[j].id){
            objectsFound.Push(productList[i].id);
        }       
    }
}
console.log(objectsFound);

Pour répondre à votre question exacte, si vous recherchez simplement une valeur dans un objet, vous pouvez utiliser une boucle unique for in.

var vendors = [
    {
      Name: 'Magenic',
      ID: 'ABC'
     },
    {
      Name: 'Microsoft',
      ID: 'DEF'
    } 
];

for(var ojectNumbers in vendors){
    if(vendors[ojectNumbers].Name === 'Magenic'){
        console.log('object contains Magenic');
    }
}
1
Spangle

Vous pouvez essayer cela son travail pour moi.

const _ = require('lodash');

var arr = [
  {
    name: 'Jack',
    id: 1
  },
  {
    name: 'Gabriel',
    id: 2
  },
  {
    name: 'John',
    id: 3
  }
]

function findValue(value) {
  return _.filter(arr, function (object) {
    return object['name'].toLowerCase().indexOf(value.toLowerCase()) >= 0;
  });
}

console.log(findValue('jack'))
//[ { name: 'Jack', id: 1 } ]
1
jenish

Mon approche pour résoudre ce problème consiste à utiliser ES6 et à créer une fonction qui effectue la vérification pour nous. L'avantage de cette fonction est qu'elle peut être réutilisée dans votre projet pour vérifier n'importe quel tableau d'objets à l'aide des variables key et value à vérifier.

Assez parler, voyons le code

Tableau

const ceos = [
  {
    name: "Jeff Bezos",
    company: "Amazon"
  }, 
  {
    name: "Mark Zuckerberg",
    company: "Facebook"
  }, 
  {
    name: "Tim Cook",
    company: "Apple"
  }
];

Une fonction

const arrayIncludesInObj = (arr, key, valueToCheck) => {
  let found = false;

  arr.some(value => {
    if (value[key] === valueToCheck) {
      found = true;
      return true; // this will break the loop once found
    }
  });

  return found;
}

Appel/Utilisation

const found = arrayIncludesInObj(ceos, "name", "Tim Cook"); // true

const found = arrayIncludesInObj(ceos, "name", "Tim Bezos"); // false
0
Rotimi Best

Sinon, vous pouvez faire:

const find = (key, needle) => return !!~vendors.findIndex(v => (v[key] === needle));
0
BrunoWest

var without2 = (arr, args) => arr.filter(v => v.id !== args.id); .__ Exemple:

without2([{id:1},{id:1},{id:2}],{id:2})

Résultat: Sans2 ([{id: 1}, {id: 1}, {id: 2}], {id: 2})

0
behzad abbasi

Beaucoup de réponses ici sont bonnes et assez faciles. Mais si votre tableau d'objets a un ensemble de valeurs fixe, vous pouvez utiliser l'astuce suivante:

Mappez tout le nom dans un objet.

vendors = [
    {
      Name: 'Magenic',
      ID: 'ABC'
     },
    {
      Name: 'Microsoft',
      ID: 'DEF'
    }
];

var dirtyObj = {}
for(var count=0;count<vendors.length;count++){
   dirtyObj[vendors[count].Name] = true //or assign which gives you true.
}

Maintenant, ce dirtyObj, vous pouvez utiliser encore et encore sans aucune boucle.

if(dirtyObj[vendor.Name]){
  console.log("Hey! I am available.");
}
0
jesusverma

Test des éléments du tableau:

JS offre des fonctions de tableau qui vous permettent d'y parvenir relativement facilement. Ils sont les suivants:

  1. Array.prototype.filter: Prend une fonction de rappel qui est un test, le tableau est ensuite itéré sur son rappel et filtré en fonction de ce rappel. n nouveau tableau filtré est retourné.
  2. Array.prototype.some: Prend une fonction de rappel qui est un test, le tableau est ensuite itéré sur son rappel et si un élément réussit le test,le booléen true est renvoyé. Sinon false est retourné

Les détails sont mieux expliqués via un exemple:

Exemple:

vendors = [
    {
      Name: 'Magenic',
      ID: 'ABC'
     },
    {
      Name: 'Microsoft',
      ID: 'DEF'
    } //and so on goes array... 
];

// filter returns a new array, we instantly check if the length 
// is longer than zero of this newly created array
if (vendors.filter(company => company.Name === 'Magenic').length ) {
  console.log('I contain Magenic');
}

// some would be a better option then filter since it directly returns a boolean
if (vendors.some(company => company.Name === 'Magenic')) {
  console.log('I also contain Magenic');
}

Prise en charge du navigateur:

Ces 2 fonctions sont ES6, tous les navigateurs ne les prennent pas en charge. Pour surmonter cela, vous pouvez utiliser un polyfill. Voici le polyfill pour Array.prototype.some (de MDN):

if (!Array.prototype.some) {
  Array.prototype.some = function(fun, thisArg) {
    'use strict';

    if (this == null) {
      throw new TypeError('Array.prototype.some called on null or undefined');
    }

    if (typeof fun !== 'function') {
      throw new TypeError();
    }

    var t = Object(this);
    var len = t.length >>> 0;

    for (var i = 0; i < len; i++) {
      if (i in t && fun.call(thisArg, t[i], i, t)) {
        return true;
      }
    }

    return false;
  };
}
0