Comment vérifier si un tableau contient une valeur en JavaScript?

4001

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

C'est la seule façon que je connais de le faire:

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

Existe-t-il un moyen meilleur et plus concis pour y parvenir?

Ceci est très étroitement lié à la question Stack Overflow La meilleure façon de trouver un élément dans un tableau JavaScript? qui traite de la recherche d'objets dans un tableau à l'aide de indexOf.

Brad
la source
49
vient d'être testé: votre chemin est en fait le plus rapide pour tous les navigateurs: jsperf.com/find-element-in-obj-vs-array/2 (à part le pré-enregistrement de a.length dans une variable) tout en utilisant indexOf (comme dans $ .inArray) est beaucoup plus lent
Jörn Berkefeld
17
beaucoup ont répondu que le tableau # indexOf est votre meilleur choix ici. Mais si vous voulez quelque chose qui peut être correctement converti en booléen, utilisez ceci: ~[1,2,3].indexOf(4)renverra 0 qui sera évalué comme faux, tandis que ~[1,2,3].indexOf(3)renverra -3 qui sera évalué comme vrai.
lordvlad
8
~n'est pas ce que vous voulez utiliser pour convertir en booléen, pour cela, vous en avez besoin !. Mais dans ce cas, vous voulez vérifier l'égalité avec -1, de sorte que la fonction puisse se terminer return [1,2,3].indexOf(3) === -1; ~n'est pas un binaire, elle inversera chaque bit de la valeur individuellement.
mcfedr
14
@Iordvlad renverra [1,2,3].indexOf(4)réellement -1 . Comme @mcfedr l'a souligné, ~est l' opérateur NOT au niveau du bit , voir ES5 11.4.8. Le fait est que, puisque la représentation binaire de se -1compose uniquement de 1, son complément est 0, qui est évalué comme faux. Le complément de tout autre nombre sera non nul, donc vrai. Donc, ~fonctionne très bien et est souvent utilisé en conjonction avec indexOf.
mknecht
5
Le titre est trompeur. Où est le [[1,2],[3,4]].includes([3,4])?
mplungjan le

Réponses:

4381

Les navigateurs modernes ont Array#includes, ce qui fait exactement cela et est largement pris en charge par tout le monde sauf IE:

console.log(['joe', 'jane', 'mary'].includes('jane')); //true

Vous pouvez également utiliser Array#indexOfce qui est moins direct, mais ne nécessite pas de polyfills pour les navigateurs obsolètes.


De nombreux frameworks proposent également des méthodes similaires:

Notez que certains frameworks implémentent cela en tant que fonction, tandis que d'autres ajoutent la fonction au prototype de tableau.

codeape
la source
42
MooTools a également Array.contains qui renvoie un booléen, ce qui ressemble à la vraie question ici.
Ryan Florence
22
prototype a également Array.includequi renvoie un booléen
user102008
46
Si vous utilisez un bon navigateur, vous pouvez simplement utiliserarray.indexOf(object) != -1
Sam Soffes
13
De plus, n'utilisez pas indexOf seul comme condition, car le premier élément renverra 0 et sera évalué comme faux
plus
241
inArrayest un nom terrible pour une fonction qui retourne l'index de l'élément, et -1s'il n'existe pas. Je m'attendrais à ce qu'un booléen soit retourné.
Tim
434

Mise à jour de 2019: cette réponse date de 2008 (11 ans!) Et n'est pas pertinente pour une utilisation JS moderne. L'amélioration des performances promise était basée sur une référence réalisée dans les navigateurs de l'époque. Il peut ne pas être pertinent pour les contextes d'exécution JS modernes. Si vous avez besoin d'une solution simple, cherchez d'autres réponses. Si vous avez besoin des meilleures performances, testez-vous par vous-même dans les environnements d'exécution pertinents.

Comme d'autres l'ont dit, l'itération à travers le tableau est probablement le meilleur moyen, mais il a été prouvé qu'une whileboucle décroissante est le moyen le plus rapide d'itérer en JavaScript. Vous voudrez donc peut-être 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 également étendre le prototype Array:

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
Damir Zekić
la source
22
"Prouvé" est un mot fort. Les moteurs JS s'améliorent constamment et le temps d'exécution mesuré il y a 3 ans est terriblement dépassé.
orip
2
@Damir - Je suis d'accord. Modifiez peut-être l'exemple pour utiliser indexOf s'il est disponible, afin que les personnes qui copient-collent ce code à l'aveugle obtiennent les meilleures performances possibles.
orip
1
@cbmeeks ouais, il faut vraiment faire attention. C'était probablement un cas de faire for (o in array)qui ne devrait pas être fait lors de la boucle à travers le tableau en général ...
Damir Zekić
1
La meilleure façon de le faire est de vérifier si [1, 2, 3] .indexOf (1)> -1
Devin G Rhode
207

indexOf peut-être, mais c'est une "extension JavaScript de 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 n'offre pas d'alternative à cela, mais vous pouvez ajouter des fonctionnalités similaires aux tableaux dans Internet Explorer (et autres navigateurs qui ne prennent pas en charge indexOf) si vous le souhaitez, comme le révèle une recherche rapide sur Google (par exemple, celui-ci ).

cic
la source
en fait, il existe un exemple d'implémentation de l'extension indexOf pour les navigateurs qui ne la prennent pas en charge sur la page developer.mozilla.org à laquelle vous êtes lié.
Lloyd Cotten
en fait, si vous ajoutez indexof au prototype d'Array pour les navigateurs qui ne le prennent pas en charge (ie IE7), ils essaieront également de boucler sur cette fonction lors de la boucle des éléments du tableau. méchant.
CpILL
est-il applicable pour vérifier l'objet.? je ne pense pas que cela fonctionne dans le cas de l'objet
Himesh Aadeshara
169

ECMAScript 7 présente 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 deuxième argument facultatif fromIndex:

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

Contrairement indexOf, qui utilise Strict Equality Comparison , includescompare à l'aide de l'algorithme d'égalité SameValueZero . Cela signifie que vous pouvez détecter si un tableau comprend NaN:

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

Contrairement à indexOf, includesne saute pas les indices manquants:

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

Actuellement, il s'agit toujours d'un brouillon mais il peut être polyfilled pour le faire fonctionner sur tous les navigateurs.

Oriol
la source
3
Non pris en charge pour IE et Microsfot Edge (2015) ( developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… )
Adriano Resende
1
Également pertinent, le tableau de compatibilité ES7 (il semble que le chrome le supporte maintenant)
styfle
est-il applicable pour vérifier l'objet.? je ne pense pas que cela fonctionne dans le cas de l'objet
Himesh Aadeshara
128

Les meilleures réponses supposent des types primitifs mais si vous voulez savoir si un tableau contient un objet avec un trait, Array.prototype.some () 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 à ce sujet est que l'itération est abandonnée une fois que l'élément est trouvé, ce qui évite les cycles d'itération inutiles.

En outre, il s'intègre parfaitement dans une ifinstruction car il renvoie un booléen:

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

* Comme l'a souligné jamess dans le commentaire, au moment de cette réponse, septembre 2018, Array.prototype.some()est entièrement pris en charge: table de support caniuse.com

Michael
la source
1
À compter d'aujourd'hui, septembre 2018, Array.prototype.some () est entièrement pris en charge: table de support
caniuse.com
1
Travailler dans Node> = 8.10 pour AWS Node.js Lambda, c'est donc très bien. Solution très propre et simple! 👍🏻
Jordanie
1
@jamess Il peut être bien pris en charge, mais n'oubliez pas que Arrow functionsdans cet exemple, il n'est pas si bien pris en charge. Pour plus de détails, voir ici: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Kamil Witkowski
Fait un court-circuit? Ou itère-t-il l'ensemble du tableau même s'il a trouvé une valeur?
Douglas Gaskell
@DouglasGaskell, il abandonne l'itération une fois trouvée (mentionnée dans la réponse)
Michael
112

Disons que vous avez défini un tableau comme ceci:

const array = [1, 2, 3, 4]

Vous trouverez ci-dessous trois façons de vérifier s'il y 3en a. Tous reviennent soit trueou false.

Méthode Native Array (depuis ES2016) ( tableau de compatibilité )

array.includes(3) // true

Comme méthode de tableau personnalisé (avant ES2016)

// Prefixing the method with '_' to avoid name clashes
Object.defineProperty(Array.prototype, '_includes', { value: function (v) { return this.indexOf(v) !== -1 }})
array._includes(3) // true

Fonction simple

const includes = (a, v) => a.indexOf(v) !== -1
includes(array, 3) // true
William malo
la source
Il retourne vrai si "b" est dans le tableau "a" ... Je ne sais pas comment l'expliquer autrement ...
william malo
4
Cette partie, je ne comprends pas "!! ~". Et je pense que cela ne fonctionnera pas dans IE8 car IE8 ne prend pas en charge indexOf () sur l'objet Array.
svlada
62
"~" est un opérateur qui plancher, inverse et soustrait 1 d'un nombre. indexOf renvoie -1 en cas d'échec, donc "~" transforme -1 en "0". en utilisant "!!" transforme les nombres en boléens (!! 0 === false)
william malo
1
Cool, mais sérieusement pour des raisons de simplicité y pas seulement a.indexOf (b)> - 1, puisque "> -1" .length === "!! ~" .length
super
2
J'appellerais le manque de connaissances sur les effets des opérateurs booléens non professionnel. Mais je suis d'accord sur la valeur d'un code lisible, je l'envelopperais certainement dans une fonction clairement étiquetée. Et c'est exactement ce que font la plupart des principaux frameworks JS.
okdewit
79

Voici une implémentation compatible JavaScript 1.6 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;
        };
}
Már Örlygsson
la source
Cela a l'air génial, mais un peu confus: * Les tests sur les lignes 1 et 3 ne sont-ils pas équivalents? * Ne serait-il pas préférable de tester le prototype et d'ajouter la fonction à Array.prototype si nécessaire?
Avi Flax
10
Ils ne sont pas équivalents. [].indexOfest un raccourci pour Array.prototype.indexOf. Nous, les programmeurs Javascript paranoïaques, évitons d'étendre à tout prix les prototypes natifs.
Már Örlygsson
1
N'est-ce pas [].indexOfcréer un nouveau tableau et y accéder indexOf, alors Array.prototype.indexOfqu'il accède simplement au prototype directement?
alex
3
@alex yes [].indexOf === Array.prototype.indexOf(essayez-le dans FireBug), mais inversement [].indexOf !== Array.indexOf.
Már Örlygsson
57

Utilisation:

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

// Usage
if(isInArray(my_array, "my_value"))
{
    //...
}
Matías Cánepa
la source
25
x ? true : falseest généralement redondant. C'est ici.
Ry-
@minitech Pourquoi dites-vous que c'est redondant?
Matías Cánepa
8
array.indexOf(search) >= 0est déjà un booléen. Justement return array.indexOf(search) >= 0.
Ry-
@minitech bien merci! En fait, je ne savais pas qu'une telle construction pouvait être restituée. TIL quelque chose de nouveau.
Matías Cánepa
Littéralement, toute construction en javascript peut être retournée
BT
49

L'extension de l' Arrayobjet JavaScript est une très mauvaise idée car vous introduisez de nouvelles propriétés (vos méthodes personnalisées) dans des for-inboucles qui peuvent casser les scripts existants. Il y a quelques années, les auteurs de la bibliothèque Prototype ont dû repenser leur implémentation de bibliothèque pour supprimer ce genre de chose.

Si vous n'avez pas à vous soucier de la compatibilité avec d'autres JavaScript exécutés sur votre page, allez-y, sinon, je recommanderais la solution de fonction autonome plus maladroite mais plus sûre.

Peter Mortensen
la source
22
Je ne suis pas d'accord. Les boucles For-in ne doivent pas être utilisées pour les tableaux pour cette raison précisément. L'utilisation de boucles for-in se brisera lors de l'utilisation de l'une des bibliothèques js populaires
Tomas
Serait-ce considéré comme une correction de singe? lol Certaines personnes aiment ça.
cbmeeks
33

Bon mot:

function contains(arr, x) {
    return arr.filter(function(elem) { return elem == x }).length > 0;
}
AlonL
la source
8
array.filter(e=>e==x).length > 0est équivalent array.some(e=>e==x)mais someplus efficace
Apolo
32

En sortant des sentiers battus pendant une seconde, si vous effectuez cet appel plusieurs fois, il est beaucoup plus efficace d'utiliser un tableau associatif une carte pour effectuer des recherches à l'aide d'une fonction de hachage.

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

MattMcKnight
la source
Bien que cela soit évidemment utile pour beaucoup, il aurait été préférable qu'un extrait de code soit ajouté.
Pie 'Oh' Pah
28

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
Eduardo Cuomo
la source
24
function contains(a, obj) {
    return a.some(function(element){return element == obj;})
}

Array.prototype.some () a été ajouté à la norme ECMA-262 dans la 5e édition

dansalmo
la source
si vous utilisez es6, il peut être raccourci commecontains = (a, obj) => a.some((element) => element === obj))
diEcho
Même IE9 prend en charge Array.prototype.some () à partir d' ECMAScript 5 .
Suncat2000
19

Une solution bidirectionnelle indexOf/ lastIndexOfalternative, je l'espère, plus rapide

2015

Bien que la nouvelle méthode inclut soit très agréable, le support est pratiquement nul pour l'instant.

Cela fait longtemps que je pensais à un moyen de remplacer les fonctions slow indexOf / lastIndexOf.

Un moyen performant a déjà été trouvé, en regardant les meilleures réponses. Parmi ceux que j'ai choisiscontainsParmi fonction publiée par @Damir Zekic qui devrait être la plus rapide. Mais il indique également que les repères datent de 2008 et sont donc dépassés.

Je préfère également whileplus for, mais pour une raison non spécifique, j'ai fini d'écrire la fonction avec une boucle for. Cela pourrait aussi être fait avec unwhile -- .

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

Lorsque vous savez que vous venez de pousser un tableau avec une valeur, l'utilisation de lastIndexOf reste probablement la meilleure solution, mais si vous devez parcourir de grands tableaux et que le résultat pourrait être partout, cela pourrait être une solution solide pour accélérer les choses.

IndexOf / lastIndexOf bidirectionnel

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');

Test de performance

http://jsperf.com/bidirectionalindexof

Comme test, j'ai créé un tableau avec 100 000 entrées.

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

J'espère que vous trouverez également cela intéressant et testez les performances.

Remarque: Comme vous pouvez le voir, j'ai légèrement modifié la containsfonction pour refléter la sortie indexOf & lastIndexOf (donc en gros trueavec indexet falseavec -1). Cela ne devrait pas lui nuire.

La variante du prototype de matrice

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ée pour retourner vrai ou faux ou même l'objet, la chaîne ou quoi que ce soit.

Et voici la whilevariante:

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 calcul simple pour obtenir l'index 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 vérifications par itération, mais cela n'est possible qu'avec un calcul plus long qui provoque le ralentissement du code.

http://jsperf.com/bidirectionalindexof/2

cocco
la source
18

Performance

Aujourd'hui 2020.01.07 j'effectue des tests sur MacOs HighSierra 10.13.6 sur Chrome v78.0.0, Safari v13.0.4 et Firefox v71.0.0 pour 15 solutions choisies. Conclusions

  • les solutions basées sur JSON, Setet étonnamment find(K, N, O) sont les plus lentes sur tous les navigateurs
  • l'es6 includes(F) est rapide uniquement sur chrome
  • les solutions basées sur for(C, D) etindexOf (G, H) sont assez rapides sur tous les navigateurs sur les petites et grandes baies, elles sont donc probablement le meilleur choix pour une solution efficace
  • les solutions où l'index diminue pendant la boucle, (B) est plus lent probablement parce que le mode de mise en cache du processeur fonctionne .
  • Je lance également un test pour un grand tableau lorsque l'élément recherché était en position 66% de la longueur du tableau, et les solutions basées sur for(C, D, E) donnent des résultats similaires (~ 630 ops / sec - mais le E sur safari et firefox était 10- 20% plus lent que C et D)

Résultats

entrez la description de l'image ici

Détails

J'exécute 2 cas de tests: pour tableau avec 10 éléments, et tableau avec 1 milion d'éléments. Dans les deux cas, nous mettons l'élément recherché au milieu du tableau.

Tableau petit - 10 éléments

Vous pouvez effectuer des tests sur votre machine ICI

entrez la description de l'image ici

Tableau grand - 1.000.000 éléments

Vous pouvez effectuer des tests sur votre machine ICI

entrez la description de l'image ici

Kamil Kiełczewski
la source
16

Si vous utilisez JavaScript 1.6 ou version ultérieure (Firefox 1.5 ou version ultérieure), vous pouvez utiliser Array.indexOf . Sinon, je pense que vous allez vous retrouver avec quelque chose de similaire à votre code d'origine.

Andru Luvisi
la source
16
function inArray(elem,array)
{
    var len = array.length;
    for(var i = 0 ; i < len;i++)
    {
        if(array[i] == elem){return i;}
    }
    return -1;
} 

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

LmC
la source
16

Nous utilisons cet extrait (fonctionne avec des objets, des tableaux, des chaînes):

/*
 * @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
});

Usage:

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
dr.dimitru
la source
15

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

  1. Garder le tableau trié à tout moment en effectuant un tri par insertion dans votre tableau (placez les nouveaux objets au bon endroit)
  2. Faire la mise à jour des objets comme une opération de suppression + insertion triée et
  3. Utilisez une recherche binaire dans votre contains(a, obj).
Ztyx
la source
2
Ou si possible, arrêtez complètement d'utiliser un tableau et utilisez plutôt un objet comme dictionnaire, comme l'ont suggéré MattMcKnight et ninjagecko.
joeytwiddle
13

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);
}

Usage:

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

Solution IE6 +:

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;
  };
}

Usage:

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

Pourquoi utiliser JSON.stringify?

Array.indexOfet Array.includes(ainsi que la plupart des réponses ici) ne comparent que par référence et non par valeur.

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

Prime

Doublure ES6 non optimisée:

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

Remarque: La comparaison des objets par valeur fonctionnera mieux si les clés sont dans le même ordre, donc pour être sûr, vous pouvez d'abord trier les clés avec un package comme celui-ci: https://www.npmjs.com/package/sort-keys


Mise à jour de la containsfonction avec une optimisation de la performance. Merci itinance de l' avoir signalé.

Igor Barbashin
la source
Ce morceau de code particulier peut fonctionner dans IE6 (non testé), mais IE ne prend pas en charge ES5 jusqu'à IE9.
Mark Reed
Pour des raisons de performances, vous devez éviter de stringifier. Au moins, vous devez éviter de JSON.stringifier le "obj" sur chaque boucle car il est coûteux et ralentira votre application. Par conséquent, vous devez le capturer avant la boucle for dans une variable temporaire
itinance
1
@itinance bon point. Mise à jour de la includesfonction avec votre suggestion. J'ai exécuté jsperf avec ma fonction. C'est environ 5 fois plus lent que les inclusions de lodash. Bien que lodash ne se compare pas en valeur et ne peut pas trouver {a: 1}dans [{a: 1}]. Je ne sais pas si une bibliothèque le fait. Mais je suis curieux de savoir s'il existe une manière plus performante et pas incroyablement complexe de le faire.
Igor Barbashin
Note tardive: cela ne fonctionne pas avec, disons, contains([{ a: 1, b: 2 }], { b: 2, a: 1 })parce que les objets stringifiés maintiennent l'ordre des propriétés.
Heretic Monkey
1
@HereticMonkey, vrai. C'est pourquoi j'ai ajouté la sort-keysnote en bas
Igor Barbashin
12

Utilisez lodash est une fonction.

Il est concis, précis et offre un excellent support multiplateforme.

La réponse acceptée ne répond même pas aux exigences.

Exigences: recommander le moyen le plus concis et le plus efficace pour savoir si un tableau JavaScript contient un objet.

Réponse acceptée:

$.inArray({'b': 2}, [{'a': 1}, {'b': 2}])
> -1

Ma recommandation:

_.some([{'a': 1}, {'b': 2}], {'b': 2})
> true

Remarques:

$ .inArray fonctionne très bien pour déterminer si une valeur scalaire existe dans un tableau de scalaires ...

$.inArray(2, [1,2])
> 1

... mais la question demande clairement un moyen efficace de déterminer si un objet est contenu dans un tableau.

Afin de gérer à la fois les scalaires et les objets, vous pouvez faire ceci:

(_.isObject(item)) ? _.some(ary, item) : (_.indexOf(ary, item) > -1)
l3x
la source
10

ECMAScript 6 a une proposition élégante à trouver.

La méthode find exécute la fonction de rappel une fois pour chaque élément présent dans le tableau jusqu'à ce qu'elle en trouve un où le rappel renvoie une valeur vraie. Si un tel élément est trouvé, find renvoie immédiatement la valeur de cet élément. Sinon, find renvoie undefined. le rappel n'est invoqué que pour les index du tableau auxquels des valeurs ont été attribuées; elle n'est pas invoquée pour les index qui ont été supprimés ou auxquels aucune valeur n'a été affectée.

Voici la documentation MDN à ce sujet.

La fonctionnalité de recherche 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 en 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;
    }
  });
}
Pradeep Mahdevu
la source
C'est maintenant un standard: ecma-international.org/ecma-262/6.0/#sec-array.prototype.find
Madbreaks
9

Bien que ce array.indexOf(x)!=-1soit le moyen le plus concis de le faire (et qui est pris en charge par les navigateurs non Internet Explorer depuis plus de dix ans ...), ce n'est pas O (1), mais plutôt O (N), ce qui est terrible. Si votre tableau ne change pas, vous pouvez convertir votre tableau en table de hachage, puis faites table[x]!==undefinedou ===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, bien que vous puissiez créer un tableau.prototype.contains pour «figer» un tableau et stocker une table de hachage dans this._cache sur deux lignes, cela donnerait des résultats erronés si vous choisissez de modifier votre tableau plus tard. JavaScript n'a pas suffisamment de crochets pour vous permet de conserver cet état, contrairement à Python par exemple.)

ninjagecko
la source
9

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

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'));

rlib
la source
5
Je pense que return proxy.has(obj)c'est beaucoup plus propre que deux lignes avec une déclaration if-else ici
Maciej Bukowski
function contains(arr, obj) { return new Set(arr).has(obj); }
Gordon Bean
8

Utilisation:

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

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

Démo

Pour savoir exactement ce que le tilde ~faire à ce stade, reportez-vous à cette question Que fait un tilde quand il précède une expression? .

Mina Gabriel
la source
5
Cela a déjà été publié il y a un an et demi, pas besoin de le répéter.
Shadow Wizard est Ear For You
3
En fait, il n'a pas été publié. Pas comme une réponse, mais comme un commentaire à une réponse, et même alors, ce n'est pas clair et concis. Merci de l'avoir publiée, Mina Gabriel.
T.CK
6

OK, vous pouvez simplement optimiser votre code pour obtenir le résultat!

Il existe de nombreuses façons de le faire qui sont plus propres et meilleures, mais je voulais juste obtenir votre modèle et l'appliquer à cela en utilisant JSON.stringify, faites simplement quelque chose comme ceci 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;
}
Alireza
la source
Note tardive: cela ne fonctionne pas avec, disons, contains([{ a: 1, b: 2 }], { b: 2, a: 1 })parce que les objets stringifiés maintiennent l'ordre des propriétés.
Heretic Monkey
5

En aucun cas le meilleur, mais je devenais juste créatif et ajoutais au répertoire.

Ne l'utilisez pas

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'));

sqram
la source
Que devez-vous utiliser sinon?
bryc
@bryc peut-être la solution acceptée, ou une autre solution d'ici. Si vous ne vous souciez pas beaucoup de la performance, vous pouvez l'utiliser
sqram
5

Surpris que cette question n'a toujours pas la dernière syntaxe ajoutée, ajoutant mes 2 cents.

Disons que nous avons un tableau d'objets arrObj et que nous voulons y rechercher obj.

Array.prototype. indexOf -> (renvoie index ou -1 ) est généralement utilisé pour trouver l'index de l'élément dans le tableau. Cela peut également être utilisé pour rechercher un objet mais ne fonctionne que si vous passez une référence au même objet.

let obj = { name: 'Sumer', age: 36 };
let arrObj = [obj, { name: 'Kishor', age: 46 }, { name: 'Rupen', age: 26 }];


console.log(arrObj.indexOf(obj));// 0
console.log(arrObj.indexOf({ name: 'Sumer', age: 36 })); //-1

console.log([1, 3, 5, 2].indexOf(2)); //3

Array.prototype. comprend -> (retourne vrai ou faux )

console.log(arrObj.includes(obj));  //true
console.log(arrObj.includes({ name: 'Sumer', age: 36 })); //false

console.log([1, 3, 5, 2].includes(2)); //true

Array.prototype. find -> (prend le rappel, retourne la première valeur / objet qui retourne vrai dans CB).

console.log(arrObj.find(e => e.age > 40));  //{ name: 'Kishor', age: 46 }
console.log(arrObj.find(e => e.age > 40)); //{ name: 'Kishor', age: 46 }

console.log([1, 3, 5, 2].find(e => e > 2)); //3

Array.prototype. findIndex -> (prend le rappel, retourne l' index de la première valeur / objet qui retourne vrai dans CB).

console.log(arrObj.findIndex(e => e.age > 40));  //1
console.log(arrObj.findIndex(e => e.age > 40)); //1

console.log([1, 3, 5, 2].findIndex(e => e > 2)); //1

Puisque find et findIndex prennent un rappel, nous pouvons extraire n'importe quel objet (même si nous n'avons pas la référence) du tableau en définissant de manière créative la vraie condition.

Sumer
la source
5

Une solution simple pour cette exigence consiste à utiliser find()

Si vous rencontrez un tableau d'objets comme ci-dessous,

var users = [{id: "101", name: "Choose one..."},
{id: "102", name: "shilpa"},
{id: "103", name: "anita"},
{id: "104", name: "admin"},
{id: "105", name: "user"}];

Ensuite, vous pouvez vérifier si l'objet avec votre valeur est déjà présent ou non

let data = users.find(object => object['id'] === '104');

si les données sont nulles, aucun administrateur, sinon, il retournera l'objet existant comme ci-dessous.

{id: "104", name: "admin"}

Ensuite, vous pouvez trouver l'index de cet objet dans le tableau et remplacer l'objet à l'aide du code ci-dessous.

let indexToUpdate = users.indexOf(data);
let newObject = {id: "104", name: "customer"};
users[indexToUpdate] = newObject;//your new object
console.log(users);

vous obtiendrez de la valeur comme ci-dessous

[{id: "101", name: "Choose one..."},
{id: "102", name: "shilpa"},
{id: "103", name: "anita"},
{id: "104", name: "customer"},
{id: "105", name: "user"}];

j'espère que cela aidera n'importe qui.

Shiva
la source
5

    function countArray(originalArray) {
     
    	var compressed = [];
    	// make a copy of the input array
    	var copyArray = originalArray.slice(0);
     
    	// first loop goes over every element
    	for (var i = 0; i < originalArray.length; i++) {
     
    		var count = 0;	
    		// loop over every element in the copy and see if it's the same
    		for (var w = 0; w < copyArray.length; w++) {
    			if (originalArray[i] == copyArray[w]) {
    				// increase amount of times duplicate is found
    				count++;
    				// sets item to undefined
    				delete copyArray[w];
    			}
    		}
     
    		if (count > 0) {
    			var a = new Object();
    			a.value = originalArray[i];
    			a.count = count;
    			compressed.push(a);
    		}
    	}
     
    	return compressed;
    };
    
    // It should go something like this:
    
    var testArray = new Array("dog", "dog", "cat", "buffalo", "wolf", "cat", "tiger", "cat");
    var newArray = countArray(testArray);
    console.log(newArray);

Sanjay Magar
la source