Kiểm tra đẳng thức thay đổi so với danh sách các giá trị


133

Tôi đang kiểm tra một biến, cho biết foosự bình đẳng với một số giá trị. Ví dụ,

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

Vấn đề là nó khá nhiều mã cho một nhiệm vụ tầm thường như vậy. Tôi đã đưa ra những điều sau đây:

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

nhưng điều này cũng không hoàn toàn hấp dẫn tôi, bởi vì tôi phải đưa ra các giá trị dư thừa cho các mục trong đối tượng.

Có ai biết một cách tốt để thực hiện kiểm tra bình đẳng đối với nhiều giá trị không?


Tôi nghĩ bối cảnh lớn hơn cần phải được tham gia khi quyết định một cái gì đó như thế này, bởi vì điều quan trọng là phải biết tại sao bạn lại đưa ra những so sánh như vậy.
Mũi nhọn

Chà, trong một trò chơi tôi đang tạo Tôi đang kiểm tra mã bàn phím để quyết định nên gọi chức năng nào. Trong các trình duyệt khác nhau, một khóa có mã khóa khác nhau xuất hiện, do đó cần phải so sánh với nhiều giá trị.
pimvdb

kiểm tra kiểm tra hiệu năng cho nhiều phương thức, toán tử logic thắng runkit.com/pramendra/58cad911146c1c00147f8d8d
Pramendra Gupta

Câu trả lời:


175

Bạn có thể sử dụng một mảng và indexOf:

if ([1,3,12].indexOf(foo) > -1)

1
Tôi thích cái này. Tôi thậm chí có thể tạo ra một hàm 'chứa' thông qua nguyên mẫu mà tôi đoán, để loại bỏ việc sử dụng> -1.
pimvdb

1
@pimvdb: Lưu ý rằng bạn có thể cần triển khai của riêng mình vì indexOfchỉ có sẵn kể từ phiên bản thứ 5 của ECMAScript.
Gumbo

Trong một câu trả lời khác, điều này cũng được đề cập đến, tôi không biết điều đó, cảm ơn
pimvdb

Là '>' bằng cách nào đó tốt hơn '! =='?
Max Waterman

117

Trong ECMA2016, bạn có thể sử dụng phương thức bao gồm . Đó là cách sạch nhất tôi từng thấy. (Được hỗ trợ bởi tất cả các trình duyệt chính, ngoại trừ IE (Polyfill có trong liên kết)

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

4
Đối với các biến if([a,b,c].includes(foo))hoặc chuỗiif(['a','b','c'].includes(foo))
Hastig Zusammenstellen

cho các biến => if([a,b,c].includes(foo))vì dấu ngoặc kép sẽ tạo thành chuỗi. @HastigZusammenstellen
iambinodstha

2
@BinodShrestha Tôi nghĩ đó là những gì tôi đã viết, trừ khi tôi thiếu một cái gì đó. "Đối với các biến .. hoặc chuỗi ..."
Hastig Zusammenstellen

16

Sử dụng các câu trả lời được cung cấp, tôi đã kết thúc như sau:

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

Nó có thể được gọi là như:

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

Chỉnh sửa: Gần đây tôi đã bắt gặp 'mẹo' này rất hữu ích nếu các giá trị là chuỗi và không chứa các ký tự đặc biệt. Đối với các ký tự đặc biệt trở nên xấu xí do thoát và cũng dễ bị lỗi hơn do đó.

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

Nói chính xác hơn, điều này sẽ kiểm tra chuỗi chính xác, nhưng sau đó lại phức tạp hơn đối với một bài kiểm tra đẳng thức đơn giản:

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

5
Trời đất ơi! Tôi ngạc nhiên khi thấy nó hoạt động - inlà một từ khóa trong Javascript. Ví dụ: chạy function in() {}; in()kết quả trong một lỗi cú pháp, ít nhất là trong Firefox và tôi không chắc tại sao mã của bạn không. :-)
Ben Blank

3
Ngoài ra, nó thường được coi là thực hành xấu để mở rộng Object.prototype, vì nó ảnh hưởng for (foo in bar)theo những cách không may. Có lẽ thay đổi nó function contains(obj) { for (var i = 1; i < arguments.length; i++) if (arguments[i] === obj) return true; return false; }và vượt qua các đối tượng như là một đối số?
Ben Trống

Cảm ơn phản ứng của bạn và Trình biên dịch đóng cửa của Google cũng trả về lỗi trong khi biên dịch trong khi bản thân mã này hoạt động rất tốt. Dù sao, nó đã được đề xuất rằng một lớp người trợ giúp có thể làm công việc này tốt hơn là mở rộng Object.prototypenhư bạn cũng đề cập. Tuy nhiên, tôi thích cách này, vì ký hiệu để kiểm tra là đáng yêu, công bằng foo.in(1, 2, "test", Infinity), dễ như ăn bánh.
pimvdb

Và việc xác định chức năng in()theo cách thông thường cũng thất bại trên Chrome, nhưng nguyên mẫu hoạt động ... :)
pimvdb

3
Mở rộng Object.prototype là một kiểu chống và không nên sử dụng. Sử dụng một chức năng thay thế.
Vernon

9

Bạn có thể viết if(foo in L(10,20,30))nếu bạn xác định L

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

    return obj;
};

Điều đó thậm chí còn rõ ràng hơn các câu trả lời trước đây, cảm ơn!
pimvdb

2
Tôi nghĩ thật thận trọng khi nhận xét rằng các hàm nguyên mẫu cũng là 'trong' một mảng / đối tượng - vì vậy nếu có một hàm 'loại bỏ' trong nguyên mẫu của một mảng / đối tượng, nó sẽ luôn trả về đúng nếu bạn viết mã 'remove' in L(1, 3, 12), mặc dù bạn đã không chỉ định 'loại bỏ' để được đưa vào danh sách.
pimvdb

7

Điều này có thể dễ dàng mở rộng và có thể đọc được:

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

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

Nhưng không nhất thiết phải dễ dàng hơn :)


Tôi thực sự đã sử dụng phương pháp này vì tôi muốn đặt một nhận xét bên cạnh mỗi giá trị để mô tả giá trị liên quan đến cái gì, đây là cách dễ đọc nhất để đạt được nó.
pholcroft

@pholcroft nếu bạn cần mô tả mỗi giá trị liên quan đến bạn nên tạo enum hoặc lớp và viết thuộc tính của bạn để có tên mô tả.
red_dorian

6
var a = [1,2,3];

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

Lưu ý rằng indexOf không có trong ECMAScript cốt lõi. Bạn sẽ cần phải có một đoạn mã cho IE và có thể các trình duyệt khác không hỗ trợ 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;
  };
}

Đây là bản sao của Mozilla trực tiếp. Đã quá lười để liên kết. developer.mozilla.org/en/JavaScript/Reference/Global_Objects/
mẹo

Có một lý do cho bithift khi bạn xác định len nếu bạn không thực sự dịch chuyển bit? Có một số ép buộc ngầm đang diễn ra ở đây?
jaredad7

3

Ngoài ra, vì các giá trị mà bạn đang kiểm tra kết quả đều là duy nhất, bạn cũng có thể sử dụng 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) );


2

Bây giờ bạn có thể có một giải pháp tốt hơn để giải quyết tình huống này, nhưng theo cách khác mà tôi thích.

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    
}

Tôi thích giải pháp trên hơn kiểm tra indexOf, nơi bạn cũng cần kiểm tra chỉ mục.

bao gồm các tài liệu

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

1

Tôi thích câu trả lời được chấp nhận, nhưng nghĩ rằng nó cũng sẽ gọn gàng để cho phép nó có được các mảng, vì vậy tôi đã mở rộng nó thành:

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

Bạn có thể loại bỏ cưỡng chế bằng cách thay đổi ==thành ===.


1

Nếu bạn có quyền truy cập vào Underscore, bạn có thể sử dụng như sau:

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

contains Được sử dụng để làm việc tại Lodash (trước V4), bây giờ bạn phải sử dụng includes

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

1

Đây là một chức năng arror trợ giúp nhỏ:

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

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

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

Thêm thông tin ở đây ...


Cách tiếp cận rất tốt: bắt đầu từ ý tưởng của bạn, bạn cũng có thể thực hiện nó mà không cần chức năng trợ giúp:const valToCheck = 'E'; const check = ['A', 'B', 'C', 'D'].some(option => option === valToCheck); // false
Giorgio Tempesta

Nhưng một khi tôi đã bắt đầu chỉnh sửa mã, tôi đã thấy nó includestrở thành lựa chọn tốt hơn, như trong câu trả lời của @ alister:const valToCheck = 'E'; const check = ['A', 'B', 'C', 'D'].includes(valToCheck); // false
Giorgio Tempesta

0

Tôi chỉ đơn giản sử dụng hàm jQuery inArray và một mảng các giá trị để thực hiện điều này:

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

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

if(test >= 0) // true

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.