Comment puis-je vérifier si un tableau inclut un objet en JavaScript?

Quelle est la manière la plus concise et efficace de savoir si un tableau JavaScript contient un objet?

C'est le seul moyen que je connaisse pour le faire:

function contains(a, obj) {
    for (var i = 0; i < a.length; i++) {
        if (a[i] === obj) {
            return true;
        }
    }
    return false;
}

y a-t-il une façon meilleure et plus concise d'y parvenir?

Ceci est très étroitement lié à la question de débordement de la pile meilleure façon de trouver un article dans un tableau JavaScript? qui traite de la recherche d'objets en un tableau utilisant indexOf .

3311
demandé sur Community 2008-10-26 02:14:40

30 réponses

les navigateurs actuels ont Array#includes , qui fait exactement que, est largement supporté , et a un polyfill pour les navigateurs plus anciens.

> ['joe', 'jane', 'mary'].includes('jane');
true 

vous pouvez également utiliser Array#indexOf , ce qui est moins direct, mais ne nécessite pas de Polyfills pour les navigateurs périmés.

jQuery offre $.inArray , qui est fonctionnellement équivalent à Array#indexOf .

trait de soulignement.js , une bibliothèque utilitaire JavaScript, offre _.contains(list, value) , alias _.include(list, value) , qui utilisent tous les deux indexOf en interne si passé un tableau JavaScript.

certains autres cadres offrent des méthodes similaires:

remarquez que certains frameworks implémentent ceci comme une fonction, tandis que d'autres ajoutent la fonction au prototype du tableau.

3738
répondu codeape 2018-07-31 17:29:16

mise à jour: comme @orip le mentionne dans les commentaires, Le benchmark lié a été fait en 2008, de sorte que les résultats peuvent ne pas être pertinents pour les navigateurs modernes. Cependant, vous avez probablement besoin de cela pour prendre en charge les navigateurs non-modernes de toute façon et ils n'ont probablement pas été mis à jour depuis. Toujours tester par vous-même.

comme d'autres l'ont dit, l'itération à travers le tableau est probablement la meilleure façon, mais il a été prouvé qu'un décroissant while boucle est le moyen le plus rapide d'itérer en JavaScript. Vous pouvez donc réécrire votre code comme suit:

function contains(a, obj) {
    var i = a.length;
    while (i--) {
       if (a[i] === obj) {
           return true;
       }
    }
    return false;
}

bien sûr, vous pouvez aussi bien étendre prototype de réseau:

Array.prototype.contains = function(obj) {
    var i = this.length;
    while (i--) {
        if (this[i] === obj) {
            return true;
        }
    }
    return false;
}

et maintenant vous pouvez simplement utiliser ce qui suit:

alert([1, 2, 3].contains(2)); // => true
alert([1, 2, 3].contains('2')); // => false
365
répondu Damir Zekić 2012-07-26 15:30:44

indexOf peut-être, mais C'est une extension JavaScript à la norme ECMA-262; en tant que telle, elle peut ne pas être présente dans d'autres implémentations de la norme."

exemple:

[1, 2, 3].indexOf(1) => 0
["foo", "bar", "baz"].indexOf("bar") => 1
[1, 2, 3].indexOf(4) => -1

AFAICS Microsoft ne pas une sorte d'alternative pour cela, mais vous pouvez ajouter des fonctionnalités similaires aux tableaux dans Internet Explorer (et les autres navigateurs qui ne sont pas soutenez indexOf ) si vous voulez, comme un la recherche rapide de Google révèle (par exemple, celui-ci ).

163
répondu cic 2011-08-11 23:41:11

ECMAScript 7 introduit Array.prototype.includes .

Il peut être utilisé comme ceci:

[1, 2, 3].includes(2); // true
[1, 2, 3].includes(4); // false

il accepte également un second argument optionnel fromIndex :

[1, 2, 3].includes(3, 3); // false
[1, 2, 3].includes(3, -1); // true

Contrairement à indexOf , qui utilise Égalité Stricte Comparaison , includes compare à l'aide de SameValueZero l'égalité de l'algorithme. Cela signifie que vous pouvez détecter si un tableau inclut un NaN :

[1, 2, NaN].includes(NaN); // true

également à la différence de indexOf , includes ne saute pas les indices manquants:

new Array(5).includes(undefined); // true

Actuellement, il est encore un projet, mais peut être polyfilled pour le faire fonctionner sur tous les navigateurs.

135
répondu Oriol 2016-02-08 16:53:32

b est la valeur, et a est le tableau. Il retourne true ou false :

function(a, b) {
    return a.indexOf(b) != -1
}
98
répondu william malo 2017-01-07 11:31:00

voici un JavaScript 1.6 compatible mise en œuvre de Array.indexOf :

if (!Array.indexOf)
{
  Array.indexOf = [].indexOf ?
      function (arr, obj, from) { return arr.indexOf(obj, from); }:
      function (arr, obj, from) { // (for IE6)
        var l = arr.length,
            i = from ? parseInt( (1*from) + (from<0 ? l:0), 10) : 0;
        i = i<0 ? 0 : i;
        for (; i<l; i++) {
          if (i in arr  &&  arr[i] === obj) { return i; }
        }
        return -1;
      };
}
68
répondu Már Örlygsson 2017-01-07 11:36:05

utiliser:

function isInArray(array, search)
{
    return array.indexOf(search) >= 0;
}

// Usage
if(isInArray(my_array, "my_value"))
{
    //...
}
49
répondu Matías Cánepa 2017-01-07 11:29:04

les réponses du haut supposent des types primitifs mais si vous voulez savoir si un tableau contient un objet avec un trait, tableau.prototype.certains () est une solution très élégante:

const items = [ {a: '1'}, {a: '2'}, {a: '3'} ]

items.some(item => item.a === '3')  // returns true
items.some(item => item.a === '4')  // returns false

La bonne chose, c'est que l'itération est annulée une fois que l'élément est trouvé, donc inutile d'itération cycles sont enregistrés.

aussi, il s'inscrit bien dans un if déclaration car il renvoie un booléen:

if (items.some(item => item.a === '3')) {
  // do something
}

* comme jamess l'a souligné dans le commentaire, à compter d'aujourd'hui, septembre 2018, Array.prototype.some() est entièrement soutenu: caniuse.com tableau de soutien

43
répondu Michael 2018-09-16 05:46:49

étendre L'objet JavaScript Array est une très mauvaise idée parce que vous introduisez de nouvelles propriétés (vos méthodes personnalisées) dans des boucles for-in qui peuvent briser les scripts existants. Il y a quelques années, les auteurs de la Prototype bibliothèque a dû repenser leur mise en œuvre de la bibliothèque pour supprimer justement ce genre de chose.

si vous n'avez pas à vous soucier de la compatibilité avec D'autres JavaScript tournant sur votre page, allez-y, sinon, je recommanderais la solution de fonction autonome plus embarrassante, mais plus sûre.

41
répondu Peter Mortensen 2011-08-11 23:43:55

penser hors de la boîte pour une seconde, si vous faites cet appel plusieurs fois, il est beaucoup plus efficace d'utiliser un tableau associatif une carte pour faire des recherches en utilisant une fonction de hachage.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map

25
répondu MattMcKnight 2018-05-06 18:35:49

One-liner:

function contains(arr, x) {
    return arr.filter(function(elem) { return elem == x }).length > 0;
}
22
répondu AlonL 2017-01-07 11:25:51

j'utilise ce qui suit:

Array.prototype.contains = function (v) {
    return this.indexOf(v) > -1;
}

var a = [ 'foo', 'bar' ];

a.contains('foo'); // true
a.contains('fox'); // false
21
répondu Eduardo Cuomo 2014-06-15 01:15:33
function contains(a, obj) {
    return a.some(function(element){return element == obj;})
}

"151920920 Tableau.prototype.certains () a été ajouté à la norme ECMA-262 dans la 5e édition

16
répondu dansalmo 2014-09-12 16:55:36

a hopeferately faster bidirectional indexOf / lastIndexOf alternative

2015

alors que la nouvelle méthode comprend est très agréable, le support est essentiellement zéro pour l'instant.

il y a longtemps que je pensais à une façon de remplacer le lent indexOf/latindexof fonctions.

une voie performante a déjà été trouvée, en regardant le top des réponses. Parmi ceux-ci, j'ai choisi la fonction contains Postée par @Damir Zekic qui devrait être la plus rapide. Mais il indique également que les critères de référence sont de 2008 et sont donc dépassés.

je préfère aussi while plutôt que for , mais pour une raison non spécifique j'ai terminé l'écriture de la fonction avec une boucle for. On pourrait aussi le faire avec un while -- .

j'étais curieux si l'itération était beaucoup plus lente si je vérifie les deux côtés du tableau tout en le faisant. Apparemment non, et donc cette fonction est environ deux fois plus rapide que les plus votées. Évidemment, il est aussi plus rapide que le natif. Ce dans un environnement réel, où vous ne savez jamais si la valeur recherchée est au début ou à la fin du tableau.

quand vous savez que vous venez de pousser un tableau avec une valeur, en utilisant latindexof reste probablement la meilleure solution, mais si vous devez voyager à travers de grands tableaux et le résultat pourrait être partout, cela pourrait être une solution solide pour rendre les choses plus vite.

index bidirectionnel de/dernier index de

function bidirectionalIndexOf(a, b, c, d, e){
  for(c=a.length,d=c*1; c--; ){
    if(a[c]==b) return c; //or this[c]===b
    if(a[e=d-1-c]==b) return e; //or a[e=d-1-c]===b
  }
  return -1
}

//Usage
bidirectionalIndexOf(array,'value');

essai de Performance

http://jsperf.com/bidirectionalindexof

comme test j'ai créé un tableau avec des entrées de 100k.

Trois requêtes: au début, au milieu et à la fin du tableau.

j'espère que vous trouverez aussi cela intéressant et tester la performance.

Note: Comme vous pouvez le voir j'ai légèrement modifié la fonction contains pour refléter l'indexOf & latindexof sortie (donc essentiellement true avec le index et false avec -1 ). Qui ne devrait pas lui nuire.

Le tableau prototype variante

Object.defineProperty(Array.prototype,'bidirectionalIndexOf',{value:function(b,c,d,e){
  for(c=this.length,d=c*1; c--; ){
    if(this[c]==b) return c; //or this[c]===b
    if(this[e=d-1-c] == b) return e; //or this[e=d-1-c]===b
  }
  return -1
},writable:false, enumerable:false});

// Usage
array.bidirectionalIndexOf('value');

La fonction peut également être facilement modifié pour retournez true ou false ou même l'objet, la chaîne ou quoi que ce soit d'autre.

et voici la variante while :

function bidirectionalIndexOf(a, b, c, d){
  c=a.length; d=c-1;
  while(c--){
    if(b===a[c]) return c;
    if(b===a[d-c]) return d-c;
  }
  return c
}

// Usage
bidirectionalIndexOf(array,'value');

Comment est-ce possible?

je pense que le simple calcul pour obtenir l'indice réfléchi dans un tableau est si simple qu'il est deux fois plus rapide que de faire une itération de boucle réelle.

voici un exemple complexe faisant trois contrôles par itération, mais cela est seulement possible avec plus de calculs qui provoque le ralentissement du code.

http://jsperf.com/bidirectionalindexof/2

13
répondu cocco 2017-01-07 11:42:35

si vous vérifiez à plusieurs reprises l'existence d'un objet dans un tableau, vous devriez peut-être regarder dans

  1. garder le tableau trié en tout temps en faisant insertion tri dans votre tableau (mettez les nouveaux objets à la bonne place)
  2. Make updating objects as remove+tried insert operation et
  3. Utiliser un binaire de recherche recherche dans votre contains(a, obj) .
11
répondu Ztyx 2011-02-05 18:02:43
function inArray(elem,array)
{
    var len = array.length;
    for(var i = 0 ; i < len;i++)
    {
        if(array[i] == elem){return i;}
    }
    return -1;
} 

retourne l'index du tableau s'il est trouvé, ou -1 s'il n'est pas trouvé

11
répondu LmC 2014-09-06 16:22:05

nous utilisons cet extrait (fonctionne avec des objets, tableaux, cordes):

/*
 * @function
 * @name Object.prototype.inArray
 * @description Extend Object prototype within inArray function
 *
 * @param {mix}    needle       - Search-able needle
 * @param {bool}   searchInKey  - Search needle in keys?
 *
 */
Object.defineProperty(Object.prototype, 'inArray',{
    value: function(needle, searchInKey){

        var object = this;

        if( Object.prototype.toString.call(needle) === '[object Object]' || 
            Object.prototype.toString.call(needle) === '[object Array]'){
            needle = JSON.stringify(needle);
        }

        return Object.keys(object).some(function(key){

            var value = object[key];

            if( Object.prototype.toString.call(value) === '[object Object]' || 
                Object.prototype.toString.call(value) === '[object Array]'){
                value = JSON.stringify(value);
            }

            if(searchInKey){
                if(value === needle || key === needle){
                return true;
                }
            }else{
                if(value === needle){
                    return true;
                }
            }
        });
    },
    writable: true,
    configurable: true,
    enumerable: false
});

Utilisation:

var a = {one: "first", two: "second", foo: {three: "third"}};
a.inArray("first");          //true
a.inArray("foo");            //false
a.inArray("foo", true);      //true - search by keys
a.inArray({three: "third"}); //true

var b = ["one", "two", "three", "four", {foo: 'val'}];
b.inArray("one");         //true
b.inArray('foo');         //false
b.inArray({foo: 'val'})   //true
b.inArray("{foo: 'val'}") //false

var c = "String";
c.inArray("S");        //true
c.inArray("s");        //false
c.inArray("2", true);  //true
c.inArray("20", true); //false
10
répondu dr.dimitru 2014-09-10 12:12:52

si vous utilisez JavaScript 1.6 ou plus tard (Firefox 1.5 ou plus tard), vous pouvez utiliser le tableau .index de . Sinon, je pense que vous allez finir avec quelque chose de similaire à votre code d'origine.

9
répondu Andru Luvisi 2008-10-25 22:44:57

alors que array.indexOf(x)!=-1 est la façon la plus concise de le faire (et a été pris en charge par les navigateurs Non-Internet Explorer depuis plus de dix ans...), ce n'est pas O(1), mais O(N), qui est terrible. Si votre tableau ne sera pas changer, vous pouvez convertir votre tableau en un hashtable, puis faire table[x]!==undefined ou ===undefined :

Array.prototype.toTable = function() {
    var t = {};
    this.forEach(function(x){t[x]=true});
    return t;
}

Démo:

var toRemove = [2,4].toTable();
[1,2,3,4,5].filter(function(x){return toRemove[x]===undefined})

(Malheureusement, alors que vous pouvez créer un Tableau.prototype.contient de "geler" un tableau et stocker une table de hachage._cache en deux lignes, cela donnerait de mauvais résultats si vous choisissez d'éditer votre tableau plus tard. JavaScript a des crochets insuffisants pour vous permettre de garder cet état, contrairement à Python par exemple.)

8
répondu ninjagecko 2017-01-07 11:30:42

ECMAScript 6 a une élégante proposition sur find.

la méthode find exécute la fonction callback une fois pour chaque élément présent dans le tableau jusqu'à ce qu'il en trouve un où callback renvoie un true valeur. Si un tel élément est trouvé, trouver renvoie immédiatement la valeur de cet élément. Sinon, les retours de find ne sont pas définis. le rappel est invoqué seulement pour les index du tableau qui ont assigné des valeurs; il n'est pas invoquée pour les indices qui ont été supprimé ou qui n'ont jamais été affectées des valeurs.

Voici la "documentation MDN à ce sujet.

la fonctionnalité find fonctionne comme ceci.

function isPrime(element, index, array) {
    var start = 2;
    while (start <= Math.sqrt(element)) {
        if (element % start++ < 1) return false;
    }
    return (element > 1);
}

console.log( [4, 6, 8, 12].find(isPrime) ); // Undefined, not found
console.log( [4, 5, 8, 12].find(isPrime) ); // 5

vous pouvez l'utiliser dans ECMAScript 5 et ci-dessous par définissant la fonction .

if (!Array.prototype.find) {
  Object.defineProperty(Array.prototype, 'find', {
    enumerable: false,
    configurable: true,
    writable: true,
    value: function(predicate) {
      if (this == null) {
        throw new TypeError('Array.prototype.find called on null or undefined');
      }
      if (typeof predicate !== 'function') {
        throw new TypeError('predicate must be a function');
      }
      var list = Object(this);
      var length = list.length >>> 0;
      var thisArg = arguments[1];
      var value;

      for (var i = 0; i < length; i++) {
        if (i in list) {
          value = list[i];
          if (predicate.call(thisArg, value, i, list)) {
            return value;
          }
        }
      }
      return undefined;
    }
  });
}
7
répondu Pradeep Mahdevu 2017-01-07 11:27:22

Solution qui fonctionne dans tous les navigateurs modernes:

function contains(arr, obj) {
  const stringifiedObj = JSON.stringify(obj); // Cache our object to not call `JSON.stringify` on every iteration
  return arr.some(item => JSON.stringify(item) === stringifiedObj);
}

Utilisation:

contains([{a: 1}, {a: 2}], {a: 1}); // true

IE6+ solution:

function contains(arr, obj) {
  var stringifiedObj = JSON.stringify(obj)
  return arr.some(function (item) {
    return JSON.stringify(item) === stringifiedObj;
  });
}

// .some polyfill, not needed for IE9+
if (!('some' in Array.prototype)) {
  Array.prototype.some = function (tester, that /*opt*/) {
    for (var i = 0, n = this.length; i < n; i++) {
      if (i in this && tester.call(that, this[i], i, this)) return true;
    } return false;
  };
}

Utilisation:

contains([{a: 1}, {a: 2}], {a: 1}); // true

Pourquoi utiliser JSON.stringify ?

Array.indexOf et Array.includes (ainsi que la plupart des réponses ici) comparer uniquement par référence et non par valeur.

[{a: 1}, {a: 2}].includes({a: 1});
// false, because {a: 1} is a new object

Bonus

one-liner ES6 Non optimisé:

[{a: 1}, {a: 2}].some(item => JSON.stringify(item) === JSON.stringify({a: 1));
// true

Note: Comparer des objets en valeur fonctionnera mieux si les clés sont dans le même ordre, donc pour être sûr vous pourriez trier les clés en premier avec un paquet comme celui-ci: https://www.npmjs.com/package/sort-keys


mise à Jour contains fonction avec une perf d'optimisation. Merci itinance pour l'avoir montré.

7
répondu Igor Barbashin 2017-07-04 23:34:23

utiliser:

var myArray = ['yellow', 'orange', 'red'] ;

alert(!!~myArray.indexOf('red')); //true

Démo

pour savoir exactement ce que fait le tilde ~ à ce point, référez-vous à cette question Que fait un tilde lorsqu'il précède une expression? .

6
répondu Mina Gabriel 2017-05-23 12:03:09

Voici comment Prototype n'est :

/**
 *  Array#indexOf(item[, offset = 0]) -> Number
 *  - item (?): A value that may or may not be in the array.
 *  - offset (Number): The number of initial items to skip before beginning the
 *      search.
 *
 *  Returns the position of the first occurrence of `item` within the array &mdash; or
 *  `-1` if `item` doesn't exist in the array.
**/
function indexOf(item, i) {
  i || (i = 0);
  var length = this.length;
  if (i < 0) i = length + i;
  for (; i < length; i++)
    if (this[i] === item) return i;
  return -1;
}

Voir aussi ici pour la façon dont ils l'accrochent.

3
répondu Ken 2009-08-27 17:10:53

utiliser:

Array.prototype.contains = function(x){
  var retVal = -1;

  // x is a primitive type
  if(["string","number"].indexOf(typeof x)>=0 ){ retVal = this.indexOf(x);}

  // x is a function
  else if(typeof x =="function") for(var ix in this){
    if((this[ix]+"")==(x+"")) retVal = ix;
  }

  //x is an object...
  else {
    var sx=JSON.stringify(x);
    for(var ix in this){
      if(typeof this[ix] =="object" && JSON.stringify(this[ix])==sx) retVal = ix;
    }
  }

  //Return False if -1 else number if numeric otherwise string
  return (retVal === -1)?false : ( isNaN(+retVal) ? retVal : +retVal);
}

je sais que c'est pas la meilleure façon d'aller, mais puisqu'il n'est pas natif IComparable façon d'interagir entre les objets, je suppose que c'est aussi proche que vous pouvez obtenir pour comparer deux entités dans un tableau. En outre, étendre objet Array n'est peut-être pas une chose sage à faire, mais parfois C'est OK (si vous êtes au courant de cela et du compromis).

3
répondu Carlos A 2017-01-07 11:32:23

On peut utiliser Set qui a la méthode "a()":

function contains(arr, obj) {
  var proxy = new Set(arr);
  if (proxy.has(obj))
    return true;
  else
    return false;
}

var arr = ['Happy', 'New', 'Year'];
console.log(contains(arr, 'Happy'));
3
répondu rlib 2017-01-07 11:46:13

vous pouvez également utiliser ce truc:

var arrayContains = function(object) {
  return (serverList.filter(function(currentObject) {
    if (currentObject === object) {
      return currentObject
    }
    else {
      return false;
    }
  }).length > 0) ? true : false
}
3
répondu user2724028 2017-01-07 11:47:45

OK, vous pouvez juste optimiser votre code pour obtenir le résultat! Il y a de nombreuses façons de faire cela qui sont plus propres et mieux, mais je voulais juste obtenir votre modèle et s'appliquer à cela en utilisant JSON.stringify , simplement faire quelque chose comme ça dans votre cas:

function contains(a, obj) {
    for (var i = 0; i < a.length; i++) {
        if (JSON.stringify(a[i]) === JSON.stringify(obj)) {
            return true;
        }
    }
    return false;
}
3
répondu Alireza 2018-03-06 10:28:08

comme d'autres l'ont mentionné , vous pouvez utiliser Array.indexOf , mais il n'est pas disponible dans tous les navigateurs. Voici le code à partir de https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/indexOf pour le faire fonctionner même dans les navigateurs plus anciens.

indexOf est un ajout récent à la norme ECMA-262; en tant que tel, il peut ne pas être présent dans tous les navigateurs. Vous pouvez contourner cela en insérant le code suivant à le début de vos scripts, permettant l'utilisation index des implémentations qui ne le supportent pas nativement. Ce l'algorithme est exactement celui spécifié dans ECMA-262, 5e édition, en présumant L'objet, le typographe, le nombre, Les Maths.étage, les Maths.abs, et les Mathématiques.Max ont leur valeur d'origine.

if (!Array.prototype.indexOf) {
    Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
        "use strict";
        if (this == null) {
            throw new TypeError();
        }
        var t = Object(this);
        var len = t.length >>> 0;
        if (len === 0) {
            return -1;
        }
        var n = 0;
        if (arguments.length > 1) {
            n = Number(arguments[1]);
            if (n != n) { // shortcut for verifying if it's NaN
                n = 0;
            } else if (n != 0 && n != Infinity && n != -Infinity) {
                n = (n > 0 || -1) * Math.floor(Math.abs(n));
            }
        }
        if (n >= len) {
            return -1;
        }
        var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
        for (; k < len; k++) {
            if (k in t && t[k] === searchElement) {
                return k;
            }
        }
        return -1;
    }
}
2
répondu Simon_Weaver 2013-08-03 18:10:31

ce n'est pas le meilleur, mais je devenais créatif et j'ajoutais au répertoire.

n' utilisez pas ce

Object.defineProperty(Array.prototype, 'exists', {
  value: function(element, index) {

    var index = index || 0

    return index === this.length ? -1 : this[index] === element ? index : this.exists(element, ++index)
  }
})


// Outputs 1
console.log(['one', 'two'].exists('two'));

// Outputs -1
console.log(['one', 'two'].exists('three'));

console.log(['one', 'two', 'three', 'four'].exists('four'));
2
répondu sqram 2017-01-07 11:47:15