JavaScript'te dizenin listede olup olmadığını belirleme


263

SQL'de bir dizenin aşağıdaki gibi bir listede olup olmadığını görebiliriz:

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

Bunu JavaScript'te yapmanın iyi bir yolu nedir? Bunu yapmak çok zor:

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

Ve bunun performansından veya netliğinden emin değilim:

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

Veya anahtar işlevini kullanabilirsiniz:

var str = 'a',
   flag = false;

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

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

Ama bu korkunç bir karmaşa. Herhangi bir fikir?

Bu durumda, bir şirket intranet sayfası için olduğu gibi Internet Explorer 7'yi kullanmam gerekiyor. Yani ['a', 'b', 'c'].indexOf(str) !== -1sözdizimi şekeri olmadan doğal olarak çalışmayacak.


1
"Dize listede" ve "dizi bir nesne içerir" arasındaki farkın tam olarak ne olduğunu açıklayabilir misiniz?
Michał Perłakowski

2
@Gothdo Bir liste her zaman bir dizi olmadığından ve bir dize bir nesne olmadığından? Nasıl daha net olabilirdi?
ErikE

Bu sözü neyi durum buysa @ErikE NOT sonra bu soruyu kapalı olmalıdır başka ödül olmamalı / cevaplar izin verdi. Zaten gönderilen yanıtlar herkesin yardım alması için yeterlidir.
Vikasdeep Singh

@VicJordan Belki yorumunuzu artık geçerli olmadığı için silmek istersiniz.
ErikE

Yanıtlar:


280

Şunu arayabilirsiniz indexOf:

if (['a', 'b', 'c'].indexOf(str) >= 0) {
    //do something
}

15
Tek sorun Array.prototype.indexOfIE üzerinde çalışmayacak, ne yazık ki IE8 bile bu yöntemi yoktur.
CMS



8
@ImJasonH: o sayfadaki kod gerçekten örneğin gerçekten kötü IMHO, eğer çek Array.indexOfgeçersiz kılma önce var olan Array.prototype.indexOfvardır değil aynı şey. Mozilla tarafından yapılan uygulamayı burada bulabilirsiniz: developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Objects/…
CMS

1
@CMS, @Emtucifor dinleyin, Mozilla uygulaması çok daha iyi.
Jason Hall

230

EcmaScript 6

ES6 kullanıyorsanız, öğelerden oluşan bir dizi oluşturabilir ve aşağıdakileri kullanabilirsiniz includes:

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

Bu üzerinde bir miktar doğal faydası vardır indexOfdüzgün varlığı için test edebilirsiniz çünkü NaNlistede ve bu orta biri olarak eksik dizi elemanları eşleşebilir [1, , 2]için undefined. includesAyrıca JavaScript gibi diziler üzerinde çalışır Uint8Array.

(Örneğin IE veya Kenardan gibi) tarayıcı desteği hakkında endişe ediyorsanız, olabilir kontrol Array.includesCanIUse.Com de ve eksik bir tarayıcı veya tarayıcı sürümünü hedeflemek istiyorsanız includes, tavsiyem polyfill.io polyfilling için.

Dizi Olmadan

isInListDizelere aşağıdaki gibi yeni bir özellik ekleyebilirsiniz :

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

Sonra şöyle kullanın:

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

Aynı şeyi için de yapabilirsiniz Number.prototype.

Array.indexOf

Modern bir tarayıcı kullanıyorsanız, indexOfher zaman çalışır. Ancak, IE8 ve öncesi için bir çoklu dolguya ihtiyacınız olacak.

Eğer indexOfgetiri -1, öğe listesinde değil. Bununla birlikte, bu yöntemin düzgün bir şekilde kontrol edilmeyeceğini NaNve açık bir şekilde eşleşebilmesine undefinedrağmen, eksik bir öğeyi undefineddizideki gibi eşleştiremeyeceğini unutmayın [1, , 2].

IE için indexOfveya includesIE'de veya herhangi bir tarayıcı / sürüm eksik desteği için çoklu dolgu

Yukarıda belirtildiği gibi polyfill.io gibi bir hizmet kullanmak istemiyorsanız , her zaman kendi kaynak kodu standartlarınızla uyumlu özel çoklu dolgular ekleyebilirsiniz. Örneğin, Mozilla Geliştirici Ağı için bir tane vardır indexOf.

Internet Explorer 7 için bir çözüm yapmak zorunda kaldığım bu durumda indexOf(), standartlara uygun olmayan işlevin daha basit bir sürümünü "yuvarladım" :

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

Ancak, değiştirmenin Array.prototypeuzun vadede en iyi cevap olduğunu düşünmüyorum . Değiştirme Objectve ArrayJavaScript prototip ciddi hatalar yol açabilir. Kendi ortamınızda güvenli olup olmadığına karar vermelisiniz. Birincil not, bir dizinin (Array.prototype özellikleri eklediğinde) yinelenmesinin for ... inyeni işlev adını anahtarlardan biri olarak döndürmesidir:

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!

Kodunuz şimdi çalışabilir, ancak gelecekte birinin devralınan anahtarlara karşı gayretle koruma sağlamayan bir üçüncü taraf JavaScript kitaplığı veya eklentisi eklediği anda her şey bozulabilir.

Bu kırılmaları önlemek için eski yolu nesne aslında olmayan bir miras ile mülkiyet olarak olup olmadığını görmek için her değerini kontrol etmek, numaralandırma sırasında olduğu if (arr.hasOwnProperty(x))ve ancak o zaman o ile çalışmak x.

Bu ekstra tuş sorunu önlemek için yeni ES6 yolu kullanmaktır ofyerine in, for (let x of arr). Ancak, tüm kodlarınızın ve üçüncü taraf kitaplıklarının kesinlikle bu yönteme bağlı olduğunu garanti edemezseniz, bu sorunun amaçları için muhtemelen includesyukarıda belirtildiği gibi kullanmak isteyeceksiniz .


2
Burada başka iyi polyfill için indexOfMDN'yi tarafından sağlanan. Temel olarak aynı şeyi yapar, ancak kolay değerlendirme için birkaç kısa devre ile.
KyleMit

1
Downvoter: lütfen yorum yapın. Bununla ilgili sorun nedir? Bu işlev standartlarla uyumlu DEĞİLDİR ve olmaya çalışmamaktadır.
ErikE

@KyleMit bağlantısının kaydettiği çok dolgu gibi test edilmiş bir şey kullanmalısınız: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
lmiguelmh

@lmiguelmh Mozilla belgelerinin kendisinden bir bağlantı gönderdiğim "çoklu dolgu" ya ne dersiniz? Her durumda, bu işlev o kadar basit ki test konusunda fazla endişelenmiyorum. Ve "zaten test edilmiş" bir fonksiyon almamalı, ne kullandıklarını kendileri test etmelidir. Yani yorumunuz biraz yanlış. İşlevimle ilgili belirli bir kusur tespit ettiniz mi?
ErikE

@ErikE haklısın bu fonksiyon öldü ve cevabını kullanan herkes bunu bilmeli. İlk etapta bağlantınızı görmedim çünkü "cevaplar" arıyordum
lmiguelmh

53

Cevapların çoğu Array.prototype.indexOfyöntemi önermektedir, tek sorun IE9'dan önce herhangi bir IE sürümünde çalışmayacak olmasıdır .

Alternatif olarak, tüm tarayıcılarda çalışacak iki seçenek daha bırakıyorum:

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


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

Hmmm, bahsettiğiniz için teşekkürler, CMS. Sadece bu kurumsal bir intranet için ve onlar ... tahmin etmek ne ... IE kullanır. Düzenli ifade yöntemi bana willies verdiğinden, ya döngüler bir işlev yapmak ya da benim yazı (üçüncü kod bloğu) önerdiğim nesne yöntemini kullanmak zorunda kalacağım.
ErikE

13
Bu eşleşecek "HiFooThere"- /^(?:Foo|Bar|Baz)$/bunun yerine gitmek istiyorum (dize başlangıcı, yakalamayan grup, dize sonu).
TrueWill

indexOfMDN'ye göre IE 9 ve üstü sürümlerde artık desteklenmektedir .
15'te krock

28

Dizilerin indexOfdizeleri aramak için kullanılabilecek bir yöntemi vardır:

js> a = ['foo', 'bar', 'baz']
foo,bar,baz
js> a.indexOf('bar')
1
js> a.indexOf('quux')
-1

3
Bu, eski tarayıcılarda başarısız olacaktır.
epascarello

Hata ... IE'de bunun işe yaramadığından bahsetmek güzel olurdu. :)
ErikE

2
@epascarello: Sadece eski tarayıcılarda değil , IE8'de bile herhangi bir IE'de başarısız olacak :(
CMS

12

Kullandığım bir numara

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

Gibi bir şey yapabilirdin

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

voyager, soru içinde üçüncü kod bloğumun gösterdiği gibi sadece öğeyi kaldırma girişiminden daha hızlı / yavaş / daha iyi / kötü "in" kullanıyor mu? Ayrıca, bir şey üzerinde döngü olacak, ben de o zaman öğenin dizide olup olmadığını kontrol edebilirsiniz anlamaya ... sadece döngü bir işlevi sarın. Ve ne için değer var i=a.length;while (i--) {/*use a[i]*/}en hızlı döngü yöntemidir (ters sipariş kabul edilebilirse).
ErikE

@Emtucifor: gerçekten ne yaptığınıza bağlı ve sanırım farklı javascript motorlarında farklı çalışabilir. Verileriniz herhangi bir noktada bir sözlük kullanılmasını gerektiriyorsa, bu şekilde oluşturmak daha iyidir. Dict nesnesi oluşturulduktan sonra bunun motorlardaki uygulama ayrıntıları (nesne için hash tablolarının kullanımı) nedeniyle daha hızlı olacağını düşünürüm .
Esteban Küber

JavaScript'te buna diksiyon değil, nesne denir .
Solomon Ucko

8

Benimki burada:

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

Bir diziyi geçme konusunda sorun yaşıyorsanız bu daha hızlıdır:

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

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

İşte jsperf: http://jsperf.com/bmcgin-inlsit


Açıkçası, bir diziyi geçtiğiniz yer muhtemelen daha yararlı olacaktır ve muhtemelen Arrayprototipinde olmalıdır: belki böyle bir şey Array.prototype.contains.
Solomon Ucko

6

RegExpevrenseldir, ancak dizilerle çalıştığınızı anlıyorum. Bu yaklaşıma bir göz atın. Kullanmak için kullanıyorum ve çok etkili ve hızlı yanıp sönüyor!

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

rx.test(str);

Ayrıca, bazı değişiklikler de uygulayabilirsiniz:

Tek astar

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

Büyük / küçük harfe duyarlı değil

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


Ve bircok digerleri!


Normal ifade kullanmak bir grup özel karakterden kaçınmayı gerektirir. Aynı zamanda daha az açıktır. Bunun iyi bir çözüm olduğunu düşünmüyorum.
ErikE

@ErikE Rezervasyonlarınızı anlıyorum, bu yüzden RegExp kullanmayan başka bir kod ekleyerek cevabımı güncelledim, IE ile çok uyumlu, çok deyimsel ve hızlı.
sospedra

Ek kodunuz, bir Regex çözümü göndermeye karar vermeden 5 yıl önce verdiğim yanıtın neredeyse bir kopyası. Katıldığınız için teşekkür ederiz ve aynı zamanda önceki cevabınıza geri dönmenin en iyisi olduğunu düşünüyorum.
ErikE

@ErikE evet, haklısın, sorudaki cevapları kontrol etmek için kullanmıyorum. Ve bunun gerçekten benzer olduğuna katılıyorum.
sospedra

6

İndexOf kullanma (IE8 ile çalışmaz).

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

IE8'i desteklemek için Mozilla'nın indexOf'unu uygulayabilirsiniz.

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

String.prototype.match (docs) aracılığıyla Normal İfadeler.

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

}

1
Sayfadaki diğer yanıtları tam olarak çoğalttığınızı fark ettiniz mi? Bu herhangi bir değer katmaz.
ErikE

5

Görünüşe göre in_array işlevini kullanmanız gerekiyor.

jQuery -> inArray

Prototip -> Array.indexOf

Veya jQuery veya Prototype kullanmıyorsanız bu örneklere bakın:

Biçemsel not: İçerdiği şeyi isimlendiren değişkenler, içerdikleri hakkında bir şeyler söylemek için adlandırılmalıdır (isim).


Oh, değişken değillerdi ama ifadeler için rastgele yer tutuculardılar ... sadece senaryoyu nasıl kullanmayı planladığımın bir örneği.
ErikE

5

indexOf(Diğer posterlerin önerdiği) ek olarak , prototipin Enumerable.include () yöntemini kullanmak bunu daha düzenli ve özlü hale getirebilir:

var list = ['a', 'b', 'c'];
if (list.include(str)) {
  // do stuff
}

5
Enumerable.include () kullanımdan kaldırıldı, ancak Array.prototype.includes () geliyor ve IE (elbette) ve Edge (elbette) dışında çoğu tarayıcıda zaten çalışıyor.
whitebeard

2

Sorunuz ve Array.indexOf yöntemini kullanan çözüm için teşekkürler.

IMO, yazma daha basit ve okuma daha açık hale getirecek bir inList () işlevi oluşturmak için bu çözümden kodu kullandım:

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

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

KULLANIM:

if (inList('Houston', 'LA,New York,Houston') {
  // THEN do something when your string is in the list
}

1
Javascript dizi değişmezleri o kadar kolay ki, yapabildiğinizde neden bölündüğünüzü anlamıyorum 'Houston'.inList(['LA', 'New York', 'Houston']). Belki if (!String.prototype.inList) {String.prototype.inList = function(arr) {return arr.indexOf(this) >= 0};}veya whileyönteminizi kullanarak .
ErikE

0

Kimsenin bir dize ve bir liste alan basit bir işlevden bahsetmediğine şaşırdım.

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

Jim tam olarak ne önerdiğini yaptı , Sam, 27 Ağustos'ta 1:29. Aslında, seçmiş olduğum cevap hemen hemen aynı şey, sadece bir parametre yerine dizeyle bunu sağlıyor .
ErikE

Üzgünüm, Jims cevabı dediğin gibi bana garip geldi. Ve kabul ettiğiniz cevabınız int, bazı insanlar bu soruyla karşılaşabileceği gibi, bir booldönüş arıyor . Birkaç kişiye yardımcı olabileceğini düşündüm.
Samuel Parkinson

0

Benim çözüm şöyle bir sözdizimi ile sonuçlanır:

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

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

Ve bunu aşağıdaki gibi temel Nesne prototipini genişleterek uyguluyorum:

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

Alternatif olarak, yöntemi isInArray (ancak muhtemelen inArray değil) veya isIn yöntemine adlandırabiliriz.

Avantajları: Basit, anlaşılır ve kendi kendini belgeleme.


Object genişletilirken sorun olabilir. bolinfest.com/javascript/inheritance.php "Google Haritalar ekibi bunu zor bir şekilde öğrendi" başlığı altında ve tarayıcı uygulamasıyla veya diğer kullanıcı kodlarıyla uyumsuzluk altında. Hala bir dizi üzerinden yineleme hashmap oluşturulduktan sonra bir hashmap bir anahtar bulmaktan daha yavaş olduğu için ErikE'nin cevabı en iyi olduğunu düşünüyorum: myValues[key];myValues ​​bir nesne ve anahtar herhangi bir dize veya sayıdır.
HMR

-1

SLaks'ın cevabının basitleştirilmiş bir versiyonu da çalışır:

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

... çünkü dizeler bir çeşit dizidir. :)

Gerekirse, Internet Explorer için indexof işlevini benden önce açıklandığı gibi uygulayın.


1
Bu yalnızca amaçlanmayan tek harfli dizelerle çalışır.
ErikE
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.