Wie überprüfe ich, ob ein Array einen Wert in JavaScript enthält?

3996

Was ist der präziseste und effizienteste Weg, um herauszufinden, ob ein JavaScript-Array einen Wert enthält?

Dies ist der einzige Weg, den ich kenne:

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

Gibt es einen besseren und prägnanteren Weg, um dies zu erreichen?

Dies hängt sehr eng mit der Frage zum Stapelüberlauf zusammen. Der beste Weg, um ein Element in einem JavaScript-Array zu finden? Hiermit wird das Suchen von Objekten in einem Array mithilfe von indexOf.

Brad
quelle
49
soeben getestet: Ihr Weg ist tatsächlich der schnellste für alle Browser: jsperf.com/find-element-in-obj-vs-array/2 (abgesehen vom Vorsparen einer Länge in einer Variablen) bei Verwendung von indexOf (wie in $) .inArray) ist viel langsamer
Jörn Berkefeld
17
Viele haben geantwortet, dass das Array # indexOf hier Ihre beste Wahl ist. Wenn Sie jedoch etwas möchten, das korrekt in Boolean umgewandelt werden kann, verwenden Sie Folgendes: ~[1,2,3].indexOf(4)Gibt 0 zurück, was als falsch ausgewertet wird, während ~[1,2,3].indexOf(3)-3 zurückgegeben wird, was als wahr ausgewertet wird.
Lordvlad
8
~ist nicht das, was Sie verwenden möchten, um in einen Booleschen Wert zu konvertieren !. In diesem Fall möchten Sie jedoch die Gleichheit mit -1 überprüfen, damit die Funktion möglicherweise return [1,2,3].indexOf(3) === -1; ~nicht binär endet. Sie invertiert jedes Bit des Werts einzeln.
McFedr
14
@Iordvlad [1,2,3].indexOf(4)wird tatsächlich -1 zurückgeben . Wie @mcfedr hervorhob, ~handelt es sich um den bitweisen NOT-Operator , siehe ES5 11.4.8. Da die binäre Darstellung von nur -1aus Einsen besteht, ist das Komplement 0, das als falsch ausgewertet wird. Das Komplement einer anderen Zahl ist ungleich Null, daher wahr. Funktioniert also ~einwandfrei und wird oft in Verbindung mit verwendet indexOf.
mknecht
5
Der Titel ist irreführend. Wo ist das [[1,2],[3,4]].includes([3,4])?
Mplungjan

Antworten:

4375

Moderne Browser haben Array#includes, was genau das tut und von allen außer IE weitgehend unterstützt wird:

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

Sie können auch verwenden Array#indexOf, was weniger direkt ist, aber keine Polyfüllungen für veraltete Browser erfordert.


Viele Frameworks bieten auch ähnliche Methoden an:

Beachten Sie, dass einige Frameworks dies als Funktion implementieren, während andere die Funktion dem Array-Prototyp hinzufügen.

Codeape
quelle
42
MooTools hat auch Array.contains, das einen Booleschen Wert zurückgibt, was hier wie die eigentliche Frage klingt.
Ryan Florence
22
Prototyp hat auch, Array.includedass ein Boolescher
Wert zurückgegeben wird
46
Wenn Sie einen guten Browser verwenden, können Sie einfach verwendenarray.indexOf(object) != -1
Sam Soffes
13
Verwenden Sie auch indexOf nicht alleine als Bedingung, da das erste Element 0 zurückgibt und als falsch ausgewertet wird
plus
241
inArrayist ein schrecklicher Name für eine Funktion, die den Index des Elements zurückgibt, und -1wenn es nicht existiert. Ich würde erwarten, dass ein Boolescher Wert zurückgegeben wird.
Tim
434

Update von 2019: Diese Antwort stammt aus dem Jahr 2008 (11 Jahre alt!) Und ist für die moderne JS-Nutzung nicht relevant. Die versprochene Leistungsverbesserung basierte auf einem Benchmark, der in den damaligen Browsern durchgeführt wurde. Es ist möglicherweise für moderne JS-Ausführungskontexte nicht relevant. Wenn Sie eine einfache Lösung benötigen, suchen Sie nach anderen Antworten. Wenn Sie die beste Leistung benötigen, messen Sie sich selbst in den relevanten Ausführungsumgebungen.

Wie andere gesagt haben, ist die Iteration durch das Array wahrscheinlich der beste Weg, aber es wurde bewiesen, dass eine abnehmende whileSchleife der schnellste Weg ist, um in JavaScript zu iterieren. Daher möchten Sie Ihren Code möglicherweise wie folgt umschreiben:

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

Natürlich können Sie auch den Array-Prototyp erweitern:

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

Und jetzt können Sie einfach Folgendes verwenden:

alert([1, 2, 3].contains(2)); // => true
alert([1, 2, 3].contains('2')); // => false
Damir Zekić
quelle
22
"Bewährt" ist ein starkes Wort. JS-Engines verbessern sich ständig und die vor 3 Jahren gemessene Ausführungszeit ist schrecklich veraltet.
Orip
2
@ Damir - ich stimme zu. Ändern Sie möglicherweise das Beispiel, um indexOf zu verwenden, falls verfügbar, damit Benutzer, die diesen Code blind kopieren, die bestmögliche Leistung erzielen.
Orip
1
@cbmeeks Ja, Pflege ist definitiv erforderlich. Es war wahrscheinlich ein Fall, for (o in array)der nicht gemacht werden sollte, wenn man das Array im Allgemeinen
durchläuft
1
Der beste Weg, dies zu tun, ist zu überprüfen, ob [1, 2, 3] .indexOf (1)> -1
Devin G Rhode
207

indexOf Vielleicht, aber es ist eine "JavaScript-Erweiterung des ECMA-262-Standards; als solche ist sie möglicherweise in anderen Implementierungen des Standards nicht vorhanden."

Beispiel:

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

AFAICS Microsoft bietet keine Alternative dazu an, aber Sie können Arrays in Internet Explorer (und anderen Browsern, die dies nicht unterstützen indexOf) ähnliche Funktionen hinzufügen, wenn Sie dies möchten, wie eine schnelle Google-Suche zeigt (z. B. diese) ).

cic
quelle
Tatsächlich gibt es ein Beispiel für die Implementierung der indexOf-Erweiterung für Browser, die sie auf der von Ihnen verlinkten Seite developer.mozilla.org nicht unterstützen.
Lloyd Cotten
Wenn Sie dem Prototyp von Array für Browser, die dies nicht unterstützen (z. B. IE7), indexof hinzufügen, versuchen diese auch, diese Funktion zu durchlaufen, wenn sie die Elemente im Array durchlaufen. böse.
CpILL
Ist es anwendbar, nach dem Objekt zu suchen? Ich glaube nicht, dass es im Fall des Objekts
funktioniert
169

ECMAScript 7 wird vorgestellt Array.prototype.includes.

Es kann folgendermaßen verwendet werden:

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

Es akzeptiert auch ein optionales zweites Argument fromIndex:

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

Im Gegensatz zu indexOf, die verwendet strikte Gleichheit Vergleich , includesvergleicht mit SameValueZero Gleichheit Algorithmus. Das bedeutet, dass Sie erkennen können, ob ein Array Folgendes enthält NaN:

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

Auch im Gegensatz zu indexOf, includesnicht überspringen Indizes fehlen:

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

Derzeit ist es noch ein Entwurf, kann aber mehrfach ausgefüllt werden , damit er in allen Browsern funktioniert.

Oriol
quelle
3
Nicht unterstützt für IE und Microsfot Edge (2015) ( developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… )
Adriano Resende
1
Ebenfalls relevant ist die ES7-Kompatibilitätstabelle (es sieht so aus, als würde Chrome sie jetzt unterstützen)
styfle
Ist es anwendbar, nach dem Objekt zu suchen? Ich glaube nicht, dass es im Fall des Objekts
funktioniert
128

Die Top-Antworten setzen primitive Typen voraus. Wenn Sie jedoch herausfinden möchten, ob ein Array ein Objekt mit einem bestimmten Merkmal enthält, ist Array.prototype.some () eine sehr elegante Lösung:

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

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

Das Schöne daran ist, dass die Iteration abgebrochen wird, sobald das Element gefunden wurde, sodass unnötige Iterationszyklen verschont bleiben.

Außerdem passt es gut in eine ifAnweisung, da es einen Booleschen Wert zurückgibt:

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

* Wie Jamess im Kommentar betonte, wird zum Zeitpunkt dieser Antwort im September 2018 Array.prototype.some()die Support-Tabelle von caniuse.com vollständig unterstützt

Michael
quelle
1
Ab heute, September 2018, wird Array.prototype.some () vollständig unterstützt: caniuse.com Support-Tabelle
Jamess
1
Arbeiten in Node> = 8.10 für AWS Node.js Lambda, das ist also großartig. Sehr saubere und einfache Lösung! 👍🏻
Jordanien
1
@jamess Es kann gut unterstützt werden, aber denken Sie daran, dass Arrow functionsin diesem Beispiel nicht so gut unterstützt werden. Weitere Details finden Sie hier: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Kamil Witkowski
Kurzschluss? Oder iteriert es das gesamte Array, auch wenn es einen Wert gefunden hat?
Douglas Gaskell
@DouglasGaskell bricht die einmal gefundene Iteration ab (in der Antwort erwähnt)
Michael
112

Angenommen, Sie haben ein Array wie folgt definiert:

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

Im Folgenden finden Sie drei Möglichkeiten, um zu überprüfen, ob dort eine 3vorhanden ist. Alle von ihnen kehren entweder trueoder zurück false.

Native Array-Methode (seit ES2016) ( Kompatibilitätstabelle )

array.includes(3) // true

Als benutzerdefinierte Array-Methode (vor 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

Einfache Funktion

const includes = (a, v) => a.indexOf(v) !== -1
includes(array, 3) // true
William Malo
quelle
Es gibt true zurück, wenn "b" im Array "a" ist ... Ich weiß nicht, wie ich es sonst erklären soll ...
William Malo
4
Diesen Teil verstehe ich nicht "!! ~". Und ich denke, dass dies in IE8 nicht funktioniert, da IE8 indexOf () für Array-Objekte nicht unterstützt.
Svlada
62
"~" ist ein Operator, der 1 von einer Zahl abhebt, invertiert und subtrahiert. indexOf gibt -1 zurück, wenn dies fehlschlägt. "~" verwandelt -1 in "0". mit "!!" verwandelt Zahlen in Boleans (!! 0 === false)
William Malo
1
Cool, aber der Einfachheit halber ernsthaft nicht nur a.indexOf (b)> - 1, da "> -1" .length === "!! ~" .length
super
2
Ich würde den Mangel an Wissen über die Auswirkungen von Booleschen Operatoren als unprofessionell bezeichnen. Aber ich stimme dem Wert von lesbarem Code zu, ich würde dies sicherlich in eine klar gekennzeichnete Funktion einwickeln. Und genau das tun die meisten wichtigen JS-Frameworks.
Okdewit
79

Hier ist eine JavaScript 1.6-kompatible Implementierung von 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
quelle
Das sieht gut aus, ist aber etwas verwirrt: * Sind die Tests in den Zeilen 1 und 3 nicht gleichwertig? * Wäre es nicht besser, den Prototyp zu testen und die Funktion bei Bedarf zu Array.prototype hinzuzufügen?
Avi Flax
10
Sie sind nicht gleichwertig. [].indexOfist eine Abkürzung für Array.prototype.indexOf. Wir paranoid-defensiven Javascript-Programmierer vermeiden es um jeden Preis, native Prototypen zu erweitern.
Már Örlygsson
1
Wird nicht [].indexOfein neues Array erstellt und dann zugegriffen indexOf, während Array.prototype.indexOfnur direkt auf den Prototyp zugegriffen wird?
alex
3
@alex ja [].indexOf === Array.prototype.indexOf(probiere es in FireBug aus), aber umgekehrt [].indexOf !== Array.indexOf.
Már Örlygsson
57

Verwenden:

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

// Usage
if(isInArray(my_array, "my_value"))
{
    //...
}
Matías Cánepa
quelle
25
x ? true : falseist normalerweise redundant. Es ist hier.
Ry-
@minitech Warum ist es Ihrer Meinung nach überflüssig?
Matías Cánepa
8
array.indexOf(search) >= 0ist schon ein Boolescher Wert. Einfach return array.indexOf(search) >= 0.
Ry-
@minitech gut danke! Eigentlich wusste ich nicht, dass eine solche Konstruktion zurückgegeben werden kann. Bis etwas Neues.
Matías Cánepa
Buchstäblich jedes Konstrukt in Javascript kann zurückgegeben werden
BT
49

Das Erweitern des JavaScript- ArrayObjekts ist eine wirklich schlechte Idee, da Sie neue Eigenschaften (Ihre benutzerdefinierten Methoden) in for-inSchleifen einfügen, die vorhandene Skripts beschädigen können. Vor einigen Jahren mussten die Autoren der Prototype- Bibliothek ihre Bibliotheksimplementierung überarbeiten, um genau diese Dinge zu entfernen.

Wenn Sie sich keine Gedanken über die Kompatibilität mit anderem JavaScript machen müssen, das auf Ihrer Seite ausgeführt wird, versuchen Sie es. Andernfalls würde ich die umständlichere, aber sicherere Lösung für freistehende Funktionen empfehlen.

Peter Mortensen
quelle
22
Ich stimme dir nicht zu. For-In-Schleifen sollten aus genau diesem Grund nicht für Arrays verwendet werden. Die Verwendung von For-In-Schleifen wird unterbrochen, wenn eine der beliebten JS-Bibliotheken verwendet wird
Tomas,
Würde dies als Affen-Patching angesehen werden? lol Manche Leute mögen das.
cbmeeks
33

Einzeiler:

function contains(arr, x) {
    return arr.filter(function(elem) { return elem == x }).length > 0;
}
AlonL
quelle
8
array.filter(e=>e==x).length > 0ist gleichbedeutend mit array.some(e=>e==x)aber someeffizienter
Apolo
32

Wenn Sie für eine Sekunde über den Tellerrand hinaus denken und diesen Aufruf viele Male ausführen, ist es weitaus effizienter, ein assoziatives Array und eine Map zu verwenden, um mithilfe einer Hash-Funktion nachzuschlagen.

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

MattMcKnight
quelle
Obwohl dies offensichtlich für viele hilfreich ist, wäre es besser gewesen, wenn ein Code-Snippet hinzugefügt worden wäre.
Pie 'Oh' Pah
28

Ich benutze folgendes:

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

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

a.contains('foo'); // true
a.contains('fox'); // false
Eduardo Cuomo
quelle
24
function contains(a, obj) {
    return a.some(function(element){return element == obj;})
}

Array.prototype.some () wurde in der 5. Ausgabe zum ECMA-262-Standard hinzugefügt

Dansalmo
quelle
Wenn Sie es6 verwenden, kann es alscontains = (a, obj) => a.some((element) => element === obj))
diEcho
Sogar IE9 unterstützt Array.prototype.some () ab ECMAScript 5 .
Suncat2000
19

Eine hoffentlich schnellere bidirektionale indexOf/ lastIndexOfAlternative

2015

Während die neue Methode enthält, ist sehr nett, aber die Unterstützung ist im Moment Null.

Es ist lange her, dass ich mir überlegt habe, wie ich die langsamen Funktionen indexOf / lastIndexOf ersetzen kann.

Es wurde bereits ein performanter Weg gefunden, der sich die besten Antworten ansieht. Von diesen habe ich die containsvon @Damir Zekic gepostete Funktion ausgewählt, die die schnellste sein sollte. Es heißt aber auch, dass die Benchmarks aus dem Jahr 2008 stammen und daher veraltet sind.

Ich bevorzuge es whileauch for, aber aus keinem bestimmten Grund habe ich das Schreiben der Funktion mit einer for-Schleife beendet. Es könnte auch mit einem gemacht werden while --.

Ich war neugierig, ob die Iteration viel langsamer war, wenn ich dabei beide Seiten des Arrays überprüfe. Anscheinend nein, und so ist diese Funktion ungefähr zweimal schneller als die am besten bewerteten. Offensichtlich ist es auch schneller als das native. Dies in einer realen Umgebung, in der Sie nie wissen, ob sich der gesuchte Wert am Anfang oder am Ende des Arrays befindet.

Wenn Sie wissen, dass Sie gerade ein Array mit einem Wert verschoben haben, bleibt die Verwendung von lastIndexOf wahrscheinlich die beste Lösung. Wenn Sie jedoch große Arrays durchlaufen müssen und das Ergebnis überall sein kann, kann dies eine solide Lösung sein, um die Dinge schneller zu machen.

Bidirektionaler IndexOf / lastIndexOf

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

Leistungstest

http://jsperf.com/bidirectionalindexof

Als Test habe ich ein Array mit 100.000 Einträgen erstellt.

Drei Abfragen: am Anfang, in der Mitte und am Ende des Arrays.

Ich hoffe, Sie finden das auch interessant und testen die Leistung.

Hinweis: Wie Sie sehen, habe ich die containsFunktion geringfügig geändert , um die Ausgabe von indexOf & lastIndexOf widerzuspiegeln (also im Grunde genommen truemit indexund falsemit -1). Das sollte nicht schaden.

Die Array-Prototyp-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');

Die Funktion kann auch leicht geändert werden, um true oder false oder sogar das Objekt, die Zeichenfolge oder was auch immer zurückzugeben.

Und hier ist die 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');

Wie ist das möglich?

Ich denke, dass die einfache Berechnung, um den reflektierten Index in einem Array zu erhalten, so einfach ist, dass sie zweimal schneller ist als eine tatsächliche Schleifeniteration.

Hier ist ein komplexes Beispiel, das drei Überprüfungen pro Iteration durchführt. Dies ist jedoch nur mit einer längeren Berechnung möglich, die zu einer Verlangsamung des Codes führt.

http://jsperf.com/bidirectionalindexof/2

cocco
quelle
18

Performance

Heute 2020.01.07 führe ich Tests auf MacOs HighSierra 10.13.6 unter Chrome v78.0.0, Safari v13.0.4 und Firefox v71.0.0 für 15 ausgewählte Lösungen durch. Schlussfolgerungen

  • Lösungen auf Basis von JSON, Setund überraschend find(K, N, O) sind langsamsten auf allen Browsern
  • das es6 includes(F) ist nur auf chrom schnell
  • Die auf for(C, D) und indexOf(G, H) basierenden Lösungen sind in allen Browsern auf kleinen und großen Arrays recht schnell, sodass sie wahrscheinlich die beste Wahl für eine effiziente Lösung sind
  • Die Lösungen, bei denen der Index während der Schleife abnimmt, (B) sind wahrscheinlich langsamer, weil die Art des CPU-Cache funktioniert .
  • Ich führe auch einen Test für ein großes Array durch, wenn sich das gesuchte Element auf Position 66% der Array-Länge befand und Lösungen basierend auf for(C, D, E) ähnliche Ergebnisse liefern (~ 630 ops / s - aber das E auf Safari und Firefox war 10- 20% langsamer als C und D)

Ergebnisse

Geben Sie hier die Bildbeschreibung ein

Einzelheiten

Ich führe 2 Testfälle durch: für ein Array mit 10 Elementen und ein Array mit 1 Million Elementen. In beiden Fällen setzen wir das gesuchte Element in die Mitte des Arrays.

Array klein - 10 Elemente

Sie können HIER Tests in Ihrer Maschine durchführen

Geben Sie hier die Bildbeschreibung ein

Array groß - 1.000.000 Elemente

Sie können HIER Tests in Ihrer Maschine durchführen

Geben Sie hier die Bildbeschreibung ein

Kamil Kiełczewski
quelle
16

Wenn Sie JavaScript 1.6 oder höher (Firefox 1.5 oder höher) verwenden, können Sie Array.indexOf verwenden . Andernfalls werden Sie wahrscheinlich etwas Ähnliches wie Ihren ursprünglichen Code erhalten.

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

Gibt den Array-Index zurück, wenn er gefunden wurde, oder -1, wenn er nicht gefunden wurde

LmC
quelle
16

Wir verwenden dieses Snippet (funktioniert mit Objekten, Arrays, Strings):

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

Verwendungszweck:

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
quelle
15

Wenn Sie wiederholt prüfen, ob ein Objekt in einem Array vorhanden ist, sollten Sie dies möglicherweise untersuchen

  1. Halten Sie das Array jederzeit sortiert, indem Sie eine Einfügesortierung in Ihrem Array durchführen (neue Objekte an der richtigen Stelle platzieren).
  2. Aktualisieren Sie Objekte als entfernen + sortierte Einfügeoperation und
  3. Verwenden Sie eine binäre Suchsuche in Ihrem contains(a, obj).
Ztyx
quelle
2
Oder beenden Sie nach Möglichkeit die vollständige Verwendung eines Arrays und verwenden Sie stattdessen ein Objekt als Wörterbuch, wie von MattMcKnight und ninjagecko vorgeschlagen.
Joeytwiddle
13

Lösung, die in allen modernen Browsern funktioniert:

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

Verwendungszweck:

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

IE6 + Lösung:

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

Verwendungszweck:

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

Warum verwenden JSON.stringify?

Array.indexOfund Array.includes(wie auch die meisten Antworten hier) nur nach Referenz und nicht nach Wert vergleichen.

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

Bonus

Nicht optimierter ES6-Einzeiler:

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

Hinweis: Das Vergleichen von Objekten nach Wert funktioniert besser, wenn die Schlüssel in derselben Reihenfolge vorliegen. Aus Sicherheitsgründen können Sie die Schlüssel daher zuerst mit einem Paket wie diesem sortieren: https://www.npmjs.com/package/sort-keys


Die containsFunktion wurde mit einer Perf-Optimierung aktualisiert . Vielen Dank an itinance für den Hinweis.

Igor Barbashin
quelle
Dieser bestimmte Codeabschnitt funktioniert möglicherweise in IE6 (nicht getestet), aber IE unterstützte ES5 erst in IE9.
Mark Reed
Aus Leistungsgründen sollten Sie das Stringifizieren vermeiden. Zumindest sollten Sie es vermeiden, das "obj" in jeder Schleife mit JSON.stringify zu versehen, da es teuer ist und Ihre Anwendung verlangsamt. Daher sollten Sie es vor der for-Schleife in einer temporären Variablen
erfassen
1
@itinance guter Punkt. Die includesFunktion wurde mit Ihrem Vorschlag aktualisiert . Ich habe jsperf mit meiner Funktion ausgeführt. Es ist ungefähr 5x langsamer als das von lodash. Obwohl lodash nach Wert nicht vergleichen und nicht finden kann , {a: 1}in [{a: 1}]. Ich weiß nicht, ob eine Bibliothek das tut. Aber ich bin gespannt, ob es eine performantere und nicht wahnsinnig komplexe Art gibt, dies zu tun.
Igor Barbashin
Später Hinweis: Dies funktioniert beispielsweise nicht, contains([{ a: 1, b: 2 }], { b: 2, a: 1 })da die Zeichenfolgenobjekte die Reihenfolge der Eigenschaften beibehalten.
Heretic Monkey
1
@ HereticMonkey, stimmt. Deshalb habe ich die sort-keysNotiz unten hinzugefügt
Igor Barbashin
12

Verwenden lodash ist einige Funktion.

Es ist präzise, ​​genau und bietet hervorragende plattformübergreifende Unterstützung.

Die akzeptierte Antwort entspricht nicht einmal den Anforderungen.

Anforderungen: Empfehlen Sie die präziseste und effizienteste Methode, um herauszufinden, ob ein JavaScript-Array ein Objekt enthält.

Akzeptierte Antwort:

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

Meine Empfehlung:

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

Anmerkungen:

$ .inArray funktioniert gut, um festzustellen, ob ein Skalarwert in einem Array von Skalaren vorhanden ist ...

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

... aber die Frage fragt eindeutig nach einer effizienten Methode, um festzustellen, ob ein Objekt in einem Array enthalten ist.

Um sowohl Skalare als auch Objekte zu handhaben, können Sie Folgendes tun:

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

ECMAScript 6 hat einen eleganten Vorschlag zum Finden.

Die find-Methode führt die Rückruffunktion einmal für jedes im Array vorhandene Element aus, bis sie eines findet, bei dem der Rückruf einen wahren Wert zurückgibt. Wenn ein solches Element gefunden wird, gibt find sofort den Wert dieses Elements zurück. Andernfalls wird find als undefiniert zurückgegeben. Der Rückruf wird nur für Indizes des Arrays aufgerufen, denen Werte zugewiesen wurden. Es wird nicht für Indizes aufgerufen, die gelöscht wurden oder denen nie Werte zugewiesen wurden.

Hier ist die MDN-Dokumentation dazu .

Die Suchfunktion funktioniert folgendermaßen.

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

Sie können dies in ECMAScript 5 und darunter verwenden, indem Sie die Funktion definieren .

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
quelle
Dies ist jetzt ein Standard: ecma-international.org/ecma-262/6.0/#sec-array.prototype.find
Madbreaks
9

Während array.indexOf(x)!=-1die knappste Art und Weise, dies zu tun (und wird von Nicht-Internet Explorer - Browser für mehr als zehn Jahre ... unterstützt), ist es nicht O (1), sondern O (N), das ist schrecklich. Wenn Ihr Array nicht wird sich ändern, können Sie Ihr Array in eine Hash - Tabelle umwandeln kann, dann tun table[x]!==undefinedoder ===undefined:

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

Demo:

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

(Obwohl Sie eine Array.prototype.contains erstellen können, um ein Array "einzufrieren" und eine Hashtabelle in this._cache in zwei Zeilen zu speichern, würde dies leider zu falschen Ergebnissen führen, wenn Sie Ihr Array später bearbeiten. JavaScript hat nicht genügend Hooks Lassen Sie diesen Status im Gegensatz zu Python beibehalten.)

Ninjagecko
quelle
9

Man kann Set verwenden , das die Methode "has ()" hat:

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
quelle
5
Ich denke, es return proxy.has(obj)ist viel sauberer als zwei Zeilen mit if-else-Aussage hier
Maciej Bukowski
function contains(arr, obj) { return new Set(arr).has(obj); }
Gordon Bean
8

Verwenden:

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

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

Demo

Um genau zu wissen, was tilde ~an dieser Stelle zu tun ist, lesen Sie diese Frage. Was macht eine Tilde, wenn sie einem Ausdruck vorausgeht? .

Mina Gabriel
quelle
5
Dies wurde bereits vor anderthalb Jahren veröffentlicht, ohne dass es wiederholt werden muss.
Schatten-Assistent ist Ohr für Sie
3
Eigentlich wurde es nicht gepostet. Nicht als Antwort, sondern als Kommentar zu einer Antwort, und selbst dann ist es nicht klar und prägnant. Danke, dass du es gepostet hast, Mina Gabriel.
T.CK
6

OK, Sie können einfach Ihre optimieren Code , um das Ergebnis zu erhalten!

Es gibt viele Möglichkeiten, dies zu tun, die sauberer und besser sind, aber ich wollte nur Ihr Muster erhalten und auf dieses anwenden, indem Sie JSON.stringifyin Ihrem Fall einfach so etwas tun:

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
quelle
Später Hinweis: Dies funktioniert beispielsweise nicht, contains([{ a: 1, b: 2 }], { b: 2, a: 1 })da die Zeichenfolgenobjekte die Reihenfolge der Eigenschaften beibehalten.
Heretic Monkey
5

Auf keinen Fall das Beste, aber ich wurde nur kreativ und erweiterte das Repertoire.

Verwenden Sie dies nicht

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
quelle
Was solltest du verwenden, wenn nicht dies?
Bryc
@bryc vielleicht die akzeptierte Lösung oder eine andere Lösung von hier. Wenn Sie nicht viel
Wert
5

Überrascht, dass dieser Frage immer noch nicht die neueste Syntax hinzugefügt wurde, füge ich meine 2 Cent hinzu.

Angenommen, wir haben ein Array von Objekten arrObj und möchten darin obj suchen.

Array.prototype. indexOf -> (gibt index oder -1 zurück ) wird im Allgemeinen zum Suchen des Index des Elements im Array verwendet. Dies kann auch zum Suchen von Objekten verwendet werden, funktioniert jedoch nur, wenn Sie einen Verweis auf dasselbe Objekt übergeben.

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. enthält -> (gibt true oder false zurück )

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 -> (nimmt einen Rückruf entgegen und gibt den ersten Wert / das erste Objekt zurück, das in CB true zurückgibt).

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 -> (nimmt einen Rückruf entgegen und gibt den Index des ersten Werts / Objekts zurück, der in CB true zurückgibt).

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

Da find und findIndex einen Rückruf annehmen, können wir jedes Objekt (auch wenn wir keine Referenz haben) aus dem Array abrufen, indem wir die wahre Bedingung kreativ festlegen.

Sumer
quelle
5

Eine einfache Lösung für diese Anforderung ist die Verwendung find()

Wenn Sie eine Reihe von Objekten wie unten haben,

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

Anschließend können Sie überprüfen, ob das Objekt mit Ihrem Wert bereits vorhanden ist oder nicht

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

Wenn die Daten null sind, gibt es keinen Administrator. Andernfalls wird das vorhandene Objekt wie unten angegeben zurückgegeben.

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

Dann können Sie den Index dieses Objekts im Array finden und das Objekt mit dem folgenden Code ersetzen.

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

Sie erhalten Wert wie unten

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

hoffe, das wird jedem helfen.

Shiva
quelle
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
quelle