Periksa kesetaraan variabel terhadap daftar nilai

133

Saya sedang memeriksa variabel, katakanlah foo, untuk kesetaraan ke sejumlah nilai. Sebagai contoh,

if( foo == 1 || foo == 3 || foo == 12 ) {
    // ...
}

Intinya adalah bahwa itu agak banyak kode untuk tugas sepele seperti itu. Saya datang dengan yang berikut:

if( foo in {1: 1, 3: 1, 12: 1} ) {
    // ...
}

tetapi juga ini tidak sepenuhnya menarik bagi saya, karena saya harus memberikan nilai yang berlebihan pada item dalam objek.

Apakah ada yang tahu cara yang layak untuk melakukan pemeriksaan kesetaraan terhadap beberapa nilai?

pimvdb
sumber
Saya pikir konteks yang lebih besar perlu dilibatkan ketika memutuskan sesuatu seperti ini, karena penting untuk mengetahui mengapa Anda membuat perbandingan seperti itu.
Runcing
Nah, dalam sebuah game yang saya buat, saya memeriksa kode keyboard untuk memutuskan fungsi apa yang harus dipanggil. Di browser yang berbeda, suatu kunci memiliki kode kunci yang berbeda muncul, maka kebutuhan untuk membandingkan dengan beberapa nilai.
pimvdb
periksa tes kinerja untuk beberapa metode, operator logis memenangkan runkit.com/pramendra/58cad911146c1c00147f8d8d
Pramendra Gupta

Jawaban:

175

Anda bisa menggunakan array dan indexOf:

if ([1,3,12].indexOf(foo) > -1)
Gumbo
sumber
1
Saya suka yang ini. Bahkan mungkin untuk membuat fungsi 'berisi' melalui prototipe, saya kira, untuk menghilangkan penggunaan> -1.
pimvdb
1
@pimvdb: Perhatikan bahwa Anda mungkin memerlukan implementasi Anda sendiri karena indexOfhanya tersedia sejak ECMAScript edisi ke-5.
Gumbo
Dalam jawaban lain ini memang disebutkan juga, saya tidak tahu itu, terima kasih
pimvdb
Apakah '>' lebih baik dari '! =='?
Max Waterman
117

Di ECMA2016 Anda dapat menggunakan metode include . Itu cara terbersih yang pernah kulihat. (Didukung oleh semua browser utama, kecuali IE (Polyfill ada di tautan)

if([1,3,12].includes(foo)) {
    // ...
}
Alister
sumber
4
Untuk variabel if([a,b,c].includes(foo))atau stringif(['a','b','c'].includes(foo))
Hastig Zusammenstellen
untuk variabel => if([a,b,c].includes(foo))karena tanda kutip akan membuatnya string. @HastigZusammenstellen
iambinodstha
2
@ BinodShrestha Saya pikir itu yang saya tulis, kecuali saya kehilangan sesuatu. "Untuk variabel .. atau string ..."
Hastig Zusammenstellen
16

Dengan menggunakan jawaban yang diberikan, saya berakhir dengan yang berikut:

Object.prototype.in = function() {
    for(var i=0; i<arguments.length; i++)
       if(arguments[i] == this) return true;
    return false;
}

Ini bisa disebut seperti:

if(foo.in(1, 3, 12)) {
    // ...
}

Sunting: Saya menemukan 'trik' ini akhir-akhir ini yang berguna jika nilainya string dan tidak mengandung karakter khusus. Untuk karakter khusus menjadi jelek karena melarikan diri dan juga lebih rentan kesalahan karena itu.

/foo|bar|something/.test(str);

Untuk lebih tepatnya, ini akan memeriksa string yang tepat, tetapi sekali lagi lebih rumit untuk tes kesetaraan sederhana:

/^(foo|bar|something)$/.test(str);
pimvdb
sumber
5
Kebaikan! Saya kagum bahwa berfungsi - inadalah kata kunci dalam Javascript. Misalnya, menjalankan function in() {}; in()hasil dalam kesalahan sintaks, setidaknya di Firefox, dan saya tidak yakin mengapa kode Anda tidak. :-)
Ben Blank
3
Juga, sering dianggap praktik buruk untuk diperluas Object.prototype, karena memengaruhi for (foo in bar)dengan cara yang tidak menguntungkan. Mungkin mengubahnya ke function contains(obj) { for (var i = 1; i < arguments.length; i++) if (arguments[i] === obj) return true; return false; }dan meneruskan objek sebagai argumen?
Ben Blank
Terima kasih atas reaksi Anda, dan Google Closure Compiler juga mengembalikan kesalahan saat mengkompilasi sementara kode ini sendiri berfungsi dengan baik. Bagaimanapun, telah disarankan bahwa kelas pembantu dapat melakukan pekerjaan ini lebih baik daripada memperluas Object.prototypeseperti yang Anda sebutkan. Namun, saya lebih suka cara ini, karena notasi untuk mengeceknya bagus foo.in(1, 2, "test", Infinity), mudah, dan mudah.
pimvdb
Dan mendefinisikan fungsi in()dengan cara biasa juga gagal di Chrome, tetapi prototipe berfungsi ... :)
pimvdb
3
Memperluas Object.prototype adalah anti-pola dan tidak boleh digunakan. Gunakan fungsi sebagai gantinya.
Vernon
9

Anda dapat menulis if(foo in L(10,20,30))jika Anda Lingin

var L = function()
{
    var obj = {};
    for(var i=0; i<arguments.length; i++)
        obj[arguments[i]] = null;

    return obj;
};
Elian Ebbing
sumber
Itu bahkan lebih jelas daripada jawaban sebelumnya, terima kasih!
pimvdb
2
Saya pikir itu adalah bijaksana untuk berkomentar bahwa fungsi prototipe juga 'dalam' array / objek - jadi jika ada fungsi 'hapus' dalam prototipe array / objek, itu akan selalu kembali benar jika Anda kode 'remove' in L(1, 3, 12), meskipun Anda tidak tentukan 'hapus' untuk dimasukkan ke dalam daftar.
pimvdb
7

Ini mudah diperpanjang dan dibaca:

switch (foo) {
    case 1:
    case 3:
    case 12:
        // ...
        break

    case 4:
    case 5:
    case 6:
        // something else
        break
}

Namun belum tentu lebih mudah :)

orlp
sumber
Saya benar-benar menggunakan metode ini karena saya ingin memberikan komentar di sebelah setiap nilai untuk menggambarkan apa yang terkait dengan nilai, ini adalah cara yang paling mudah dibaca untuk mencapainya.
pholcroft
@pholcroft jika Anda perlu menjelaskan apa yang terkait dengan setiap nilai, Anda harus membuat enum, atau kelas, dan menulis properti Anda untuk memiliki nama deskriptif.
red_dorian
6
var a = [1,2,3];

if ( a.indexOf( 1 ) !== -1 ) { }

Perhatikan bahwa indexOf tidak ada dalam naskah ECMAS inti. Anda harus memiliki cuplikan untuk IE dan mungkin peramban lain yang tidak mendukung Array.prototype.indexOf.

if (!Array.prototype.indexOf)
{
  Array.prototype.indexOf = function(searchElement /*, fromIndex */)
  {
    "use strict";

    if (this === void 0 || this === null)
      throw new TypeError();

    var t = Object(this);
    var len = t.length >>> 0;
    if (len === 0)
      return -1;

    var n = 0;
    if (arguments.length > 0)
    {
      n = Number(arguments[1]);
      if (n !== n)
        n = 0;
      else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0))
        n = (n > 0 || -1) * Math.floor(Math.abs(n));
    }

    if (n >= len)
      return -1;

    var k = n >= 0
          ? n
          : Math.max(len - Math.abs(n), 0);

    for (; k < len; k++)
    {
      if (k in t && t[k] === searchElement)
        return k;
    }
    return -1;
  };
}
meder omuraliev
sumber
Ini adalah salinan Mozilla secara langsung. Terlalu malas untuk ditautkan. developer.mozilla.org/en/JavaScript/Reference/Global_Objects/…
meder omuraliev
Apakah ada alasan untuk bithift ketika Anda mendefinisikan len jika Anda tidak benar-benar menggeser bit? Apakah ada paksaan implisit yang terjadi di sini?
jaredad7
3

Selain itu, karena nilai yang Anda periksa hasilnya unik, Anda juga dapat menggunakan Set.prototype.has () .

var valid = [1, 3, 12];
var goodFoo = 3;
var badFoo = 55;

// Test
console.log( new Set(valid).has(goodFoo) );
console.log( new Set(valid).has(badFoo) );

Ivan Sivak
sumber
2

Sekarang Anda mungkin memiliki solusi yang lebih baik untuk menyelesaikan skenario ini, tetapi cara lain yang saya sukai.

const arr = [1,3,12]
if( arr.includes(foo)) { // it will return true if you `foo` is one of array values else false
  // code here    
}

Saya lebih suka solusi di atas daripada memeriksa indexOf di mana Anda perlu memeriksa indeks juga.

termasuk dokumen

if ( arr.indexOf( foo ) !== -1 ) { }
Syaikh Javed
sumber
1

Saya menyukai jawaban yang diterima, tetapi berpikir itu akan rapi untuk memungkinkannya mengambil array juga, jadi saya memperluasnya ke ini:

Object.prototype.isin = function() {
    for(var i = arguments.length; i--;) {
        var a = arguments[i];
        if(a.constructor === Array) {
            for(var j = a.length; j--;)
                if(a[j] == this) return true;
        }
        else if(a == this) return true;
    }
    return false;
}

var lucky = 7,
    more = [7, 11, 42];
lucky.isin(2, 3, 5, 8, more) //true

Anda dapat menghapus tipe pemaksaan dengan mengubah ==ke ===.

Greg Perham
sumber
1

Jika Anda memiliki akses ke Garis Bawah, Anda dapat menggunakan yang berikut:

if (_.contains([1, 3, 12], foo)) {
  // ...
}

contains dulu bekerja di Lodash juga (sebelum V4), sekarang Anda harus menggunakannya includes

if (_.includes([1, 3, 12], foo)) {
  handleYellowFruit();
}
David Salamon
sumber
1

Ini adalah fungsi aror pembantu kecil:

const letters = ['A', 'B', 'C', 'D'];

function checkInList(arr, val) {
  return arr.some(arrVal => val === arrVal);
}

checkInList(letters, 'E');   // false
checkInList(letters, 'A');   // true

Info lebih lanjut di sini ...

Pemenang
sumber
Pendekatan yang sangat baik: mulai dari ide Anda, Anda juga dapat melakukannya tanpa fungsi pembantu:const valToCheck = 'E'; const check = ['A', 'B', 'C', 'D'].some(option => option === valToCheck); // false
Giorgio Tempesta
Tapi begitu saya sudah mulai mengubah kode saya telah menemukan yang includesmenjadi pilihan yang lebih baik, seperti dalam jawaban @ alister:const valToCheck = 'E'; const check = ['A', 'B', 'C', 'D'].includes(valToCheck); // false
Giorgio Tempesta
0

Saya hanya menggunakan fungsi jQuery inArray dan array nilai untuk mencapai ini:

myArr = ["A", "B", "C", "C-"];

var test = $.inArray("C", myArr)  
// returns index of 2 returns -1 if not in array

if(test >= 0) // true
ScottyG
sumber