Stellen Sie fest, ob die Zeichenfolge in JavaScript in der Liste enthalten ist

262

In SQL können wir sehen, ob sich eine Zeichenfolge in einer Liste wie folgt befindet:

Column IN ('a', 'b', 'c')

Was ist ein guter Weg, dies in JavaScript zu tun? Es ist so klobig, das zu tun:

if (expression1 || expression2 || str === 'a' || str === 'b' || str === 'c') {
   // do something
}

Und ich bin mir nicht sicher über die Leistung oder Klarheit davon:

if (expression1 || expression2 || {a:1, b:1, c:1}[str]) {
   // do something
}

Oder man könnte die Schalterfunktion verwenden:

var str = 'a',
   flag = false;

switch (str) {
   case 'a':
   case 'b':
   case 'c':
      flag = true;
   default:
}

if (expression1 || expression2 || flag) {
   // do something
}

Aber das ist ein schreckliches Durcheinander. Irgendwelche Ideen?

In diesem Fall muss ich Internet Explorer 7 für eine Unternehmens-Intranetseite verwenden. Funktioniert also ['a', 'b', 'c'].indexOf(str) !== -1nicht nativ ohne etwas Syntaxzucker.

ErikE
quelle
1
Können Sie erklären, was genau der Unterschied zwischen "Zeichenfolge ist in Liste" und "Array enthält ein Objekt" ist?
Michał Perłakowski
2
@ Gothdo Weil eine Liste nicht immer ein Array ist und eine Zeichenfolge kein Objekt? Wie könnte es klarer sein?
ErikE
@ErikE wenn dies der Fall ist , was Sie in den genannten HINWEIS dann sollte diese Frage dort geschlossen sein sollte weiter Prämie nicht sein / erlaubt Antworten. Bereits veröffentlichte Antworten reichen aus, um Hilfe zu erhalten.
Vikasdeep Singh
@VicJordan Vielleicht möchten Sie Ihren Kommentar löschen, da er nicht mehr gilt.
ErikE

Antworten:

279

Sie können anrufen indexOf:

if (['a', 'b', 'c'].indexOf(str) >= 0) {
    //do something
}
SLaks
quelle
15
Das einzige Problem dabei Array.prototype.indexOfist, dass es im IE nicht funktioniert, leider fehlt sogar dem IE8 diese Methode.
CMS
2
Sie können es aber definieren, wenn Sie möchten. Siehe soledadpenades.com/2007/05/17/arrayindexof-in-internet-explorer
Jason Hall
8
@ImJasonH: Der Code auf dieser Seite ist meiner Meinung nach wirklich sehr, sehr schlecht, zum Beispiel die Überprüfung, ob Array.indexOfvor dem Überschreiben vorhanden ist, Array.prototype.indexOfwas nicht dasselbe ist. Ich würde die Implementierung von Mozilla empfehlen, die hier verfügbar ist: developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Objects/…
CMS
1
Hören Sie @CMS, @Emtucifor, die Mozilla-Implementierung ist viel besser.
Jason Hall
230

EcmaScript 6

Wenn Sie ES6 verwenden, können Sie ein Array der Elemente erstellen und Folgendes verwenden includes:

['a', 'b', 'c'].includes('b')

Dies hat einige inhärente Vorteile gegenüber, indexOfda es das Vorhandensein NaNin der Liste ordnungsgemäß testen und fehlende Array-Elemente wie das mittlere in [1, , 2]mit übereinstimmen kann undefined. includesfunktioniert auch mit JavaScript-typisierten Arrays wie Uint8Array.

Wenn Sie Bedenken hinsichtlich der Browserunterstützung haben (z. B. für IE oder Edge), können Sie dies bei CanIUse.Com überprüfen.Array.includes Wenn Sie auf eine fehlende Browser- oder Browserversion abzielen möchten includes, empfehle ich polyfill.io für das Polyfilling.

Ohne Array

Sie können isInListZeichenfolgen wie folgt eine neue Eigenschaft hinzufügen :

if (!String.prototype.isInList) {
   String.prototype.isInList = function() {
      let value = this.valueOf();
      for (let i = 0, l = arguments.length; i < l; i += 1) {
         if (arguments[i] === value) return true;
      }
      return false;
   }
}

Dann benutze es so:

'fox'.isInList('weasel', 'fox', 'stoat') // true
'fox'.isInList('weasel', 'stoat') // false

Sie können das Gleiche für tun Number.prototype.

Array.indexOf

Wenn Sie einen modernen Browser verwenden, indexOffunktioniert dies immer. Für IE8 und frühere Versionen benötigen Sie jedoch eine Polyfüllung.

Wenn indexOf-1 zurückgegeben wird, befindet sich das Element nicht in der Liste. Beachten Sie jedoch, dass diese Methode nicht ordnungsgemäß überprüft NaNwird und zwar mit einem expliziten undefinedElement übereinstimmen kann, jedoch nicht mit einem fehlenden Element undefinedwie im Array [1, , 2].

Polyfill für indexOfoder includesim IE oder einem anderen Browser / einer anderen Version ohne Unterstützung

Wenn Sie einen Dienst wie polyfill.io nicht wie oben erwähnt verwenden möchten , können Sie jederzeit benutzerdefinierte Polyfills in Ihren eigenen Quellcode aufnehmen, die den Standards entsprechen. Zum Beispiel hat Mozilla Developer Network eine für indexOf.

In dieser Situation, in der ich eine Lösung für Internet Explorer 7 erstellen musste, habe ich meine eigene einfachere Version der indexOf()Funktion "gerollt" , die nicht den Standards entspricht:

if (!Array.prototype.indexOf) {
   Array.prototype.indexOf = function(item) {
      var i = this.length;
      while (i--) {
         if (this[i] === item) return i;
      }
      return -1;
   }
}

Ich denke jedoch nicht, dass Änderungen Array.prototypeauf lange Sicht die beste Antwort sind. Änderungen Objectund ArrayPrototypen in JavaScript können zu schwerwiegenden Fehlern führen. Sie müssen entscheiden, ob dies in Ihrer eigenen Umgebung sicher ist. Wichtig ist, dass beim Iterieren eines Arrays (wenn Array.prototype Eigenschaften hinzugefügt hat) mit for ... inder neue Funktionsname als einer der Schlüssel zurückgegeben wird:

Array.prototype.blah = function() { console.log('blah'); };
let arr = [1, 2, 3];
for (let x in arr) { console.log(x); }
// Result:
0
1
2
blah // Extra member iterated over!

Ihr Code funktioniert jetzt möglicherweise, aber in dem Moment, in dem jemand in Zukunft eine JavaScript-Bibliothek oder ein Plugin eines Drittanbieters hinzufügt, das nicht eifrig vor geerbten Schlüsseln schützt, kann alles kaputt gehen.

Die alte Methode, um diesen Bruch zu vermeiden, besteht darin, während der Aufzählung jeden Wert zu überprüfen, um festzustellen, ob das Objekt ihn tatsächlich als nicht vererbte Eigenschaft hat, if (arr.hasOwnProperty(x))und erst dann damit zu arbeiten x.

Der neue ES6-Weg, um dieses Problem mit zusätzlichen Schlüsseln zu vermeiden, besteht darin, ofanstelle von in, for (let x of arr). Wenn Sie jedoch nicht garantieren können, dass alle Ihre Code- und Drittanbieter-Bibliotheken sich strikt an diese Methode halten, möchten Sie sie für die Zwecke dieser Frage wahrscheinlich nur includeswie oben angegeben verwenden.

ErikE
quelle
2
hier ist eine andere gute PolyFill für indexOfvon MDN zur Verfügung gestellt. Es macht im Grunde das Gleiche, aber mit ein paar Kurzschlüssen zur einfachen Auswertung.
KyleMit
1
Downvoter: bitte kommentieren. Was ist das Problem damit? Diese Funktion ist NICHT standardkonform und versucht es auch nicht.
ErikE
Sie sollten etwas verwenden, das bereits getestet wurde, wie die Polyfill, die unter @ KyleMit-Link vermerkt ist: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
lmiguelmh
@lmiguelmh Wie wäre es mit der "Polyfüllung", zu der ich selbst einen Link gepostet habe, aus den Mozilla-Dokumenten selbst? In jedem Fall ist diese Funktion so einfach, dass ich mir wirklich keine Sorgen um das Testen mache. Und jeder, der es ist, sollte keine "bereits getestete" Funktion übernehmen, sondern selbst testen, was er verwendet. Ihr Kommentar ist also etwas falsch. Haben Sie mit meiner Funktion einen bestimmten Defekt festgestellt?
ErikE
@ErikE Sie haben Recht, diese Funktion ist tot und jeder, der Ihre Antwort verwendet, sollte es wissen. Ich habe Ihren Link überhaupt nicht gesehen, weil ich nach "Antworten"
gesucht habe
53

Die meisten Antworten deuten auf die Array.prototype.indexOfMethode hin. Das einzige Problem besteht darin, dass sie in keiner IE-Version vor IE9 funktioniert .

Als Alternative lasse ich Ihnen zwei weitere Optionen, die in allen Browsern funktionieren:

if (/Foo|Bar|Baz/.test(str)) {
  // ...
}


if (str.match("Foo|Bar|Baz")) {
  // ...
}
CMS
quelle
Hmmm, danke, dass Sie das erwähnt haben, CMS. Es ist einfach so, dass dies für ein Unternehmens-Intranet ist und sie ... raten Sie mal ... IE verwenden. Da mir die Methode des regulären Ausdrucks die Willies gibt, muss ich entweder eine Funktion erstellen, die Schleifen bildet, oder die Objektmethode verwenden, die ich in meinem Beitrag vorgeschlagen habe (dritter Codeblock).
ErikE
13
Dies wird übereinstimmen "HiFooThere"- ich würde /^(?:Foo|Bar|Baz)$/stattdessen gehen (Anfang der Zeichenfolge, nicht erfassende Gruppe, Ende der Zeichenfolge).
TrueWill
indexOfwird jetzt laut IEN in IE 9 und höher unterstützt .
Rock
28

Arrays verfügen über eine indexOfMethode, mit der nach Zeichenfolgen gesucht werden kann:

js> a = ['foo', 'bar', 'baz']
foo,bar,baz
js> a.indexOf('bar')
1
js> a.indexOf('quux')
-1
Harto
quelle
3
Dies schlägt in älteren Browsern fehl.
Epascarello
Hoppla ... zu erwähnen, dass dies im IE nicht funktioniert, wäre schön gewesen. :)
ErikE
2
@epascarello: Nicht nur in älteren Browsern, es wird auf jedem IE fehlschlagen , auch in IE8 :(
CMS
12

Ein Trick, den ich benutzt habe, ist

>>> ("something" in {"a string":"", "somthing":"", "another string":""})
false
>>> ("something" in {"a string":"", "something":"", "another string":""})
true

Sie könnten so etwas tun

>>> a = ["a string", "something", "another string"];
>>> b = {};
>>> for(var i=0; i<a.length;i++){b[a[i]]="";} /* Transform the array in a dict */
>>> ("something" in b)
true
Esteban Küber
quelle
Voyager, verwendet "in" schneller / langsamer / besser / schlechter als nur den Versuch, den Gegenstand zu dereferenzieren, wie mein dritter Codeblock in meiner Frage gezeigt hat? Wenn Sie das Ding durchlaufen möchten, können Sie auch prüfen, ob sich das Element zu diesem Zeitpunkt im Array befindet. Wickeln Sie die Schleife einfach in eine Funktion. Und was es wert var i=a.length;while (i--) {/*use a[i]*/}ist , ist die schnellste Schleifenmethode (wenn die umgekehrte Reihenfolge akzeptabel ist).
ErikE
@Emtucifor: Es hängt wirklich davon ab, was Sie tun, und ich denke, dass es auf verschiedenen Javascript-Engines unterschiedlich funktionieren könnte. Wenn Ihre Daten zu irgendeinem Zeitpunkt die Verwendung eines Wörterbuchs benötigen, ist es besser, sie auf diese Weise zu erstellen. Ich würde denken, dass dies aufgrund von Implementierungsdetails auf den Engines (die Verwendung von Hash-Tabellen für Objekte) schneller sein wird, sobald das dict-Objekt erstellt wurde .
Esteban Küber
In JavaScript wird es nicht als Diktat, sondern als Objekt bezeichnet .
Solomon Ucko
8

Hier ist meins:

String.prototype.inList=function(list){
    return (Array.apply(null, arguments).indexOf(this.toString()) != -1)
}

var x = 'abc';
if (x.inList('aaa','bbb','abc'))
    console.log('yes');
else
    console.log('no');

Dieser ist schneller, wenn Sie ein Array übergeben können:

String.prototype.inList=function(list){
    return (list.indexOf(this.toString()) != -1)
}

var x = 'abc';
if (x.inList(['aaa','bbb','abc']))
    console.log('yes')

Hier ist der jsperf: http://jsperf.com/bmcgin-inlsit

Brian McGinity
quelle
Ehrlich gesagt wäre derjenige, an dem Sie ein Array übergeben, wahrscheinlich nützlicher, und es sollte sich wahrscheinlich um Arrayden Prototyp handeln: vielleicht so etwas wie Array.prototype.contains.
Solomon Ucko
6

RegExpist universell, aber ich verstehe, dass Sie mit Arrays arbeiten. Schauen Sie sich diesen Ansatz an. Ich benutze es, und es ist sehr effektiv und blitzschnell!

var str = 'some string with a';
var list = ['a', 'b', 'c'];
var rx = new RegExp(list.join('|'));

rx.test(str);

Sie können auch einige Änderungen vornehmen, z.

Einzeiler

new RegExp(list.join('|')).test(str);

Groß- und Kleinschreibung wird nicht berücksichtigt

var rx = new RegExp(list.join('|').concat('/i'));


Und viele andere!

sospedra
quelle
Für die Verwendung von Regex müssen einige Sonderzeichen vermieden werden. Es ist auch weniger klar. Ich denke nicht, dass es eine gute Lösung ist.
ErikE
@ErikE Ich verstehe Ihre Vorbehalte, daher habe ich meine Antwort aktualisiert und einen weiteren Code hinzugefügt, der RegExp nicht verwendet. Er ist mit dem Internet Explorer kompatibel, sehr idiomatisch und schnell.
Sospedra
Ihr zusätzlicher Code ist eine nahezu doppelte Antwort, die ich 5 Jahre vor Ihrer Entscheidung, eine Regex-Lösung zu veröffentlichen, bereitgestellt habe. Vielen Dank für Ihre Teilnahme. Gleichzeitig denke ich, dass es am besten ist, auf Ihre vorherige Antwort zurückzugreifen.
ErikE
@ErikE yep, du hast recht, ich benutze nicht, um nach Antworten in der Frage zu suchen. Und ich stimme zu, dass es wirklich ähnlich ist.
Sospedra
6

Verwenden von indexOf (funktioniert nicht mit IE8).

if (['apple', 'cherry', 'orange', 'banana'].indexOf(value) >= 0) {
    // found
}

Um IE8 zu unterstützen, können Sie Mozillas indexOf implementieren.

if (!Array.prototype.indexOf) {
    // indexOf polyfill code here
}

Reguläre Ausdrücke über String.prototype.match (docs).

if (fruit.match(/^(banana|lemon|mango|pineapple)$/)) {

}
Tiago Medici
quelle
1
Merkst du, dass du genau andere Antworten auf der Seite duplizierst? Dies bringt keinen Mehrwert.
ErikE
5

Sieht so aus, als müssten Sie die Funktion in_array verwenden.

jQuery -> inArray

Prototyp -> Array.indexOf

Oder sehen Sie sich diese Beispiele an, wenn Sie jQuery oder Prototype nicht verwenden:

Stilistische Anmerkung: Variablen mit dem Namen thisthing thatthing sollten benannt werden, um Ihnen etwas darüber zu sagen, was sie enthalten (Substantiv).

LG_PDX
quelle
Oh, sie waren keine Variablen, sondern als zufällige Platzhalter für Ausdrücke gedacht ... nur ein Beispiel dafür, wie ich das Skript verwenden wollte.
ErikE
5

Zusätzlich zu indexOf(was andere Poster vorgeschlagen haben) kann die Verwendung von Enumerable.include () des Prototyps dies übersichtlicher und prägnanter machen:

var list = ['a', 'b', 'c'];
if (list.include(str)) {
  // do stuff
}
pkaeding
quelle
5
Enumerable.include () ist veraltet, aber Array.prototype.includes () kommt und funktioniert bereits in den meisten Browsern außer IE (natürlich) und Edge (natürlich).
Weißbart
2

Vielen Dank für die Frage und die Lösung mit der Array.indexOf-Methode.

Ich habe den Code aus dieser Lösung verwendet, um eine inList () -Funktion zu erstellen, die IMO das Schreiben einfacher und das Lesen klarer macht:

function inList(psString, psList) 
{
    var laList = psList.split(',');

    var i = laList.length;
    while (i--) {
        if (laList[i] === psString) return true;
    }
    return false;
}

VERWENDUNG:

if (inList('Houston', 'LA,New York,Houston') {
  // THEN do something when your string is in the list
}
JMichaelTX
quelle
1
Javascript-Array-Literale sind so einfach, ich verstehe nicht, warum Sie sich teilen würden, wenn Sie könnten 'Houston'.inList(['LA', 'New York', 'Houston']). Vielleicht if (!String.prototype.inList) {String.prototype.inList = function(arr) {return arr.indexOf(this) >= 0};}oder mit Ihrer whileMethode.
ErikE
0

Ich bin überrascht, dass niemand eine einfache Funktion erwähnt hat, die eine Zeichenfolge und eine Liste enthält.

function in_list(needle, hay)
{
    var i, len;

    for (i = 0, len = hay.length; i < len; i++)
    {
        if (hay[i] == needle) { return true; }
    }

    return false;
}

var alist = ["test"];

console.log(in_list("test", alist));
Samuel Parkinson
quelle
Jim hat genau das getan, was Sie vorschlagen , Sam, am 27. August 11 um 1:29. Tatsächlich ist meine ausgewählte Antwort so ziemlich dasselbe, nur dass der String mit diesem und nicht mit einem Parameter versorgt wird.
ErikE
@ErikE Sorry, Jims Antwort kam mir seltsam vor, wie du gesagt hast. Und Ihre akzeptierte Antwort gibt eine zurück int, bei der einige Leute auf diese Frage stoßen und nach einer boolRückkehr suchen . Ich dachte, es könnte ein paar Leuten helfen.
Samuel Parkinson
0

Meine Lösung führt zu einer Syntax wie folgt:

// Checking to see if var 'column' is in array ['a', 'b', 'c']

if (column.isAmong(['a', 'b', 'c']) {
  // Do something
}

Und ich implementiere dies, indem ich den grundlegenden Objektprototyp wie folgt erweitere:

Object.prototype.isAmong = function (MyArray){
   for (var a=0; a<MyArray.length; a++) {
      if (this === MyArray[a]) { 
          return true;
      }
   }
   return false;
}

Wir könnten alternativ die Methode isInArray (aber wahrscheinlich nicht inArray) oder einfach isIn nennen.

Vorteile: Einfach, unkompliziert und selbstdokumentierend.

John Hicks
quelle
Es kann Probleme beim Erweitern des Objekts geben. bolinfest.com/javascript/inheritance.php unter "Das Google Maps-Team hat dies auf die harte Tour gelernt" und Inkompatibilität mit der Browser-Implementierung oder dem Code anderer Benutzer. Ich denke immer noch, dass ErikEs Antwort die beste ist, da das Durchlaufen eines Arrays langsamer ist als das Finden eines Schlüssels in einer Hashmap, sobald die Hashmap erstellt wurde: myValues[key];wobei myValues ​​ein Objekt und der Schlüssel eine beliebige Zeichenfolge oder Zahl ist.
HMR
-1

Eine vereinfachte Version der Antwort von SLaks funktioniert auch:

if ('abcdefghij'.indexOf(str) >= 0) {
    // Do something
}

.... da Strings selbst Arrays sind. :) :)

Implementieren Sie bei Bedarf die Indexof-Funktion für Internet Explorer wie zuvor beschrieben.

Angezerus
quelle
1
Dies funktioniert nur mit Zeichenfolgen aus einem Buchstaben, die NICHT vorgesehen waren.
ErikE