Switch on ranges of integers in JavaScript

175,605

Solution 1

Here is another way I figured it out:

const x = this.dealer;
switch (true) {
    case (x < 5):
        alert("less than five");
        break;
    case (x < 9):
        alert("between 5 and 8");
        break;
    case (x < 12):
        alert("between 9 and 11");
        break;
    default:
        alert("none");
        break;
}

Solution 2

Incrementing on the answer by MarvinLabs to make it cleaner:

var x = this.dealer;
switch (true) {
    case (x < 5):
        alert("less than five");
        break;
    case (x < 9):
        alert("between 5 and 8");
        break;
    case (x < 12):
        alert("between 9 and 11");
        break;
    default:
        alert("none");
        break;
}

It is not necessary to check the lower end of the range because the break statements will cause execution to skip remaining cases, so by the time execution gets to checking e.g. (x < 9) we know the value must be 5 or greater.

Of course the output is only correct if the cases stay in the original order, and we assume integer values (as stated in the question) - technically the ranges are between 5 and 8.999999999999 or so since all numbers in js are actually double-precision floating point numbers.

If you want to be able to move the cases around, or find it more readable to have the full range visible in each case statement, just add a less-than-or-equal check for the lower range of each case:

var x = this.dealer;
switch (true) {
    case (x < 5):
        alert("less than five");
        break;
    case (x >= 5 && x < 9):
        alert("between 5 and 8");
        break;
    case (x >= 9 && x < 12):
        alert("between 9 and 11");
        break;
    default:
        alert("none");
        break;
}

Keep in mind that this adds an extra point of human error - someone may try to update a range, but forget to change it in both places, leaving an overlap or gap that is not covered. e.g. here the case of 8 will now not match anything when I just edit the case that used to match 8.

    case (x >= 5 && x < 8):
        alert("between 5 and 7");
        break;
    case (x >= 9 && x < 12):
        alert("between 9 and 11");
        break;

Solution 3

    switch(this.dealer) {
        case 1:
        case 2:
        case 3:
        case 4:
            // Do something.
            break;
        case 5:
        case 6:
        case 7:
        case 8:
            // Do something.
            break;
        default:
            break;
    }

If you don't like the succession of cases, simply go for if/else if/else statements.

Solution 4

This does not require a switch statement. It is clearer, more concise, faster, and optimises better, to use if else statements...

var d = this.dealer;
if (1 <= d && d <= 11) { // making sure in range 1..11
    if (d <= 4) {
        alert("1 to 4");
    } else if (d <= 8) {
        alert("5 to 8");
    } else {
        alert("9 to 11");
    }
} else {
    alert("not in range");
}

Speed test

I was curious about the overhead of using a switch instead of the simpler if...else..., so I put together a jsFiddle to examine it... http://jsfiddle.net/17x9w1eL/

  • Chrome: switch was around 70% slower than if else

  • Firefox: switch was around 5% slower than if else

  • IE: switch was around 5% slower than if else

  • Safari: switch was around 95% slower than if else

Notes:

Assigning to the local variable is optional, especially if your code is going to be automatically optimised later.

For numeric ranges, I like to use this kind of construction...

if (1 <= d && d <= 11) {...}

... because to me it reads closer to the way you would express a range in maths (1 <= d <= 11), and when I'm reading the code, I can read that as "if d is between 1 and 11".

Clearer

A few people don't think this is clearer. I'd say it is not less clear as the structure is close to identical to the switch option. The main reason it is clearer is that every part of it is readable and makes simple intuitive sense.

My concern, with "switch (true)", is that it can appear to be a meaningless line of code. Many coders, reading that will not know what to make of it.

For my own code, I'm more willing to use obscure structures from time to time, but if anyone else will look at it, I try to use clearer constructs. I think it is better to use the constructs for what they are intended.

Optimisation

In a modern environment, code is often going to be minified for production, so you can write clear concise code, with readable variable names and helpful comments. There's no clear reason to use switch in this way.

I also tried putting both constructs through a minifier. The if/else structure compresses well, becoming a single short expression using nested ternary operators. The switch statement when minified remains a switch, complete with "switch", "case" and "break" tokens, and as a result is considerably longer in code.

How switch(true) works

I think "switch(true) is obscure, but it seems some people just want to use it, so here's an explanation of why it works...

A switch/case statement works by matching the part in the switch with each case, and then executing the code on the first match. In most use cases, we have a variable or non-constant expression in the switch, and then match it.

With "switch(true), we will find the first expression in the case statements that is true. If you read "switch (true)" as "find the first expression that is true", the code feels more readable.

Solution 5

If you need check ranges you are probably better off with if and else if statements, like so:

if (range > 0 && range < 5)
{
    // ..
}
else if (range > 5 && range < 9)
{
    // ..
}
else
{
    // Fall through
}

A switch could get large on bigger ranges.

Share:
175,605

Related videos on Youtube

Jaanus
Author by

Jaanus

Doing C#, Java 50-50. SOreadytohelp

Updated on May 06, 2020

Comments

  • Jaanus
    Jaanus almost 4 years

    I want to do something like this

        switch (this.dealer) {
            case 1-4: 
                // Do something.
                break;
            case 5-8: 
                // Do something.
                break;
            case 9-11: 
                // Do something.
                break;
            default:
                break;
        }
    

    What is the right syntax for this? Is it possible in JavaScript?

    So this.dealer is an integer, and if it's between those values, do something.

  • Jake Wilson
    Jake Wilson almost 11 years
    This is a better solution imo because it actually demonstrates one of the reasons switch's were invented.
  • collapsar
    collapsar about 9 years
    Imho this is very bad style - the correctness of the switch statement now depends on the order of the cases. This harms readability and maintainability, in particular for case statements that no longer fit into the current editor viewport (though some argue to avoid lengthy structures like this anyway), and afaik may actually hinder optimizations ( you can no longer order the cases according to decreasing frequency of runtime occurrence).
  • collapsar
    collapsar about 9 years
    ymmv - in fact, wrt clarity, I feel this code being harder to read than a searched switch statement. The speed tests do not convince me - the statement will be a tiny snippet of the code base. Whether or not it is worth to be optimized, only profiling or careful contextual analysis can tell, and in case it is, you usually gain more by ordering the cases by decreasing frequency of runtime occurrence. (This comment isn't mean to mark your method as inferior; as said before, ymmv, and, of course, all claims imho only ;-) ),
  • David Mason
    David Mason about 9 years
    @collapsar case statements in JavaScript are fundamentally order-dependent. It would be unwise to ever start blindly reordering the cases. That optimization you are talking about is only relevant in some very limited situations - most programs would never see any benefit from such optimizations, so I don't see any value in writing code to cater to them - it makes the rare case that such an optimization is needed a little more work, but the difference is trivial.
  • David Mason
    David Mason about 9 years
    @collapsar readability concerns are worth consideration though, and if you can consistently use a switch statement such that each case is mutually exclusive (so essentially as though it were a shorter syntax for a set of if-then-else statements) I can see the benefit on cognitive load. The addition then would be to add a >= check for the lower range to each case. If you care about premature performance micro-optimizations, keep in mind that this is one extra numeric comparison for the interpreter to deal with.
  • FluffyBeing
    FluffyBeing over 7 years
    not more clear imo
  • xtempore
    xtempore over 7 years
    @zeion How many coders do you think would immediately understand what "switch (true) {" does? My guess is not too many. Including it is what makes that code unclear.
  • xtempore
    xtempore over 7 years
    @collapsar The speed issue was more a curiosity. I thought perhaps there might be some benefit to the switch option, but there wasn't. Speed on that type of code probably isn't important, but the significant difference also tells me that the switch construct wasn't intended to be used in that way. It's a hack. It's unclear, and we already have a construct for that purpose.
  • nickcoxdotme
    nickcoxdotme almost 7 years
    Notable that today on Chrome 58.0.3029.110, I got wildly different results on that JSFiddle, with if always being slower, anywhere from 2-12% slower than switch on ~10 consecutive runs.
  • xtempore
    xtempore over 6 years
    @nickcoxdotme Just revisiting this so thought I'd recheck. Tried many times and got switch being 8% slower (on Chrome 64.0.3282.71 (Official Build) beta (64-bit)), but like I said, the speeds not the important issue, perhaps more a side-effect of what the compiler expects switch to be used for.
  • darkrat
    darkrat almost 6 years
    Just throwing my 2 cents out there ... I tend to find that choosing between a switch statement and cascading if/else statements (excluding the concerns about switch(true)) comes down to two things: 1) How many cases are there? Anything beyond 5 I find switches are easier to read. 2) How likely am I to go back and add additional cases? It's quicker to added another case than it is to add another else if block (or at least it feels that way when trying to get a hotfix out to production)
  • Femi Oni
    Femi Oni over 5 years
    This will work for small ranges, in my case where the range is bigger(>=100) this would be a nightmare to type out
  • wdetac
    wdetac almost 5 years
    you are not answering the question. op intend to use switch
  • 5413668060
    5413668060 almost 5 years
    disagree, It is much more clear to use switch
  • johny why
    johny why almost 4 years
    i agree that switch(true) is an inappropriate use of switch. However, aside from that, case statements are cleaner and easier to read than if...else statements.

Related