65

Is there an easier way to determine if a variable is equal to a range of values, such as:

if x === 5 || 6 

rather than something obtuse like:

if x === 5 || x === 6

?

7
  • 2
    Why do you consider the latter obtuse? Commented Aug 24, 2012 at 20:42
  • 1
    Because I need to write some code that checks if a variable has one of 20 values, namely, if x = "New York" || "Austin" || "Alberta", etc. Commented Aug 24, 2012 at 20:56
  • 7
    @AdamTempleton: Either put all your values in an array, and then use indexOf, or you can also use a regex /^(New York|Austin|Alberta)$/.test(x). Commented Aug 24, 2012 at 21:02
  • 1
    @AdamTempleton in which case you should rewrite your question to say so. You specifically say two in the subject. Commented Aug 24, 2012 at 22:32
  • Use s = new Set([5, 6]); s.has(x);. Not sure why I can't anser this question. Commented Jan 9, 2018 at 6:27

8 Answers 8

93

You can stash your values inside an array and check whether the variable exists in the array by using [].indexOf:

if ([5, 6].indexOf(x) > -1) {
  // ...
}

If -1 is returned then the variable doesn't exist in the array.


Alternativeley, as devmaleeq suggested in the comments, this more concise notation is possible since ES2016:

if ([5, 6].includes(x)) {
    // ...
}
Sign up to request clarification or add additional context in comments.

4 Comments

This does not work in IE < 9. See MDN's Array#indexOf Compatibility section for code that you can insert to actually make it work in IE. However, unless you are using this in several places, it would probably be faster just to use a == 1 || a == 2.
Alternatively, if you are using a JS framework, both MooTools and Prototype ensure Array#indexOf exists. jQuery, on the other hand, provides its own implementation in the form of $.inArray. I'm not familiar with any other frameworks, but I'm sure they all include such functionality in some manner.
A bit more description of the code would have been nice.
And now we have i.e. ['a','b'].includes('a')
24

Depends on what sort of test you're performing. If you've got static strings, this is very easy to check via regular expressions:

if (/^[56ab]$/.test(item)) {
//-or-
if (/^(foo|bar|baz|fizz|buzz)$/.test(item)) {
    doStuff();
} else {
    doOtherStuff();
}

If you've got a small set of values (string or number), you can use a switch:

switch (item) {
case 1:
case 2:
case 3:
    doStuff();
    break;
default:
    doOtherStuff();
    break;
}

If you've got a long list of values, you should probably use an array with ~arr.indexOf(item), or arr.contains(item):

vals = [1,3,18,3902,...];
if (~vals.indexOf(item)) {
    doStuff();
} else {
    doOtherStuff();
}

Unfortunately Array.prototype.indexOf isn't supported in some browsers. Fortunately a polyfill is available. If you're going through the trouble of polyfilling Array.prototype.indexOf, you might as well add Array.prototype.contains.

Depending on how you're associating data, you could store a dynamic list of strings within an object as a map to other relevant information:

var map = {
    foo: bar,
    fizz: buzz
}
if (item in map) {
//-or-
if (map.hasOwnProperty(item)) {
    doStuff(map[item]);
} else {
    doOtherStuff();
}

in will check the entire prototype chain while Object.prototype.hasOwnProperty will only check the object, so be aware that they are different.

Comments

18

It's perfectly fine. If you have a longer list of values, perhaps you can use the following instead:

if ([5,6,7,8].indexOf(x) > -1) {
}

Comments

7

Yes. You can use your own function. This example uses .some:

var foo = [ 5, 6 ].some(function(val) {
     return val === x;
   });

foo; // true

2 Comments

Gave you an upvote for .some, which I'd never seen before!
I think .some is only IE9 or up.
3

This is what I've decided to use:

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

You would use it like this:

var fav   = 'pear',
    fruit = ['apple', 'banana', 'orange', 'pear'],
    plu   = [4152, 4231, 3030, 4409];

if (fav.isin(fruit, plu, 'eggs', 'cheese')) {
    //do something cool
}

The advantages are:

  • it works in IE < 9;
  • it reads naturally from left to right;
  • you can feed it arrays or separate values.

If you don't want to allow type coercion (indexOf does not), change the two == to ===. As it stands:

fav = "4231";
plu.indexOf(fav) //-1
fav.isin(plu)    //true

Comments

2

no, there might be a few tricks that are case specific but in general i write code like this:

if (someVariable === 1 ||
    someVariable === 2 ||
    someVariable === 7 ||
    someVariable === 12 ||
    someVariable === 14 ||
    someVariable === 19) {

    doStuff();
    moreStuff();

} else {
    differentStuff();
}

Comments

0

The simple answer is no. You can use a switch statement, which is easier to read if you are comparing a lot of string values, but using it for two values wouldn't look any better.

Comments

-2

[Edit] this seems to work, but as Dan pointed out, it is actually a false positive. Do not use this method. I leave it here for educational purposes.

Easiest way I know :

a = [1,2,3,4,5];

if(3 in a) alert("true"); // will alert true

Tested in Chrome console. Not sure if it works in other browsers.

2 Comments

That example works by accident. Try 3 in [1, 3] - it will return false because there is no element with the index 3 in the array [1, 3]. For that matter, 3 in ['a', 'b', 'c', 'd'] will return true.
Damn, so it's a false positive. Thanks for that.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.