How can I use ranges in a switch case statement using JavaScript?
Asked Answered
E

7

58

How can I use ranges in a switch case statement using JavaScript? So, instead of writing code for each and every single possibility, I'd like to group them in ranges, For example:

switch(myInterval){
   case 0-2:
      //doStuffWithFirstRange();
      break;

   case 3-6:
      //doStuffWithSecondRange();
      break;

   case 6-7:
      //doStuffWithThirdRange();
      break;

   default:
      //doStuffWithAllOthers();
}
Engender answered 17/6, 2013 at 10:49 Comment(0)
C
130

You have at least four options:

1. List each case

As shown by LightStyle, you can list each case explicitly:

switch(myInterval){

    case 0:
    case 1:
    case 2:
        doStuffWithFirstRange();
        break;

    case 3:
    case 4:
    case 5:
        doStuffWithSecondRange();
        break;

    case 6:
    case 7:
        doStuffWithThirdRange();
        break;

    default:
        doStuffWithAllOthers();
}

2. Use if / else if / else

If the ranges are large, that gets unwieldy, so you'd want to do ranges. Note that with if...else if...else if, you don't get to the later ones if an earlier one matches, so you only have to specify the upper bound each time. I'll include the lower bound in /*...*/ for clarity, but normally you would leave it off to avoid introducing a maintenance issue (if you include both boundaries, it's easy to change one and forget to change the other):

if (myInterval < 0) {
    // I'm guessing this is an error
}
else if (/* myInterval >= 0 && */ myInterval <= 2){
    doStuffWithFirstRange();
}
else if (/* myInterval >= 3 && */ myInterval <= 5) {
    doStuffWithSecondRange();
}
else if (/* myInterval >= 6 && */ myInterval <= 7) {
    doStuffWithThirdRange();
}
else {
    doStuffWithAllOthers();
}

3. Use case with expressions:

JavaScript is unusual in that you can use expressions in the case statement, so we can write the if...else if...else if sequence above as a switch statement:

switch (true){

    case myInterval < 0:
        // I'm guessing this is an error
        break;    
    case /* myInterval >= 0 && */ myInterval <= 2:
        doStuffWithFirstRange();
        break;

    case /* myInterval >= 3 && */ myInterval <= 5:
        doStuffWithSecondRange();
        break;

    case /* myInterval >= 6 && */ myInterval <= 7:
        doStuffWithThirdRange();
        break;

    default:
        doStuffWithAllOthers();
}

I'm not advocating that, but it is an option in JavaScript, and there are times it's useful. The case statements are checked in order against the value you give in the switch. (And again, lower bounds could be omitted in many cases because they would have matched earlier.) Even though the cases are processed in source-code order, the default can appear anywhere (not just at the end) and is only processed if either no cases matched or a case matched and fell through to the default (didn't have a break; it's rare you want to do that, but it happens).

4. Use a dispatch map

If your functions all take the same arguments (and that could be no arguments, or just the same ones), another approach is a dispatch map:

In some setup code:

var dispatcher = {
    0: doStuffWithFirstRange,
    1: doStuffWithFirstRange,
    2: doStuffWithFirstRange,

    3: doStuffWithSecondRange,
    4: doStuffWithSecondRange,
    5: doStuffWithSecondRange,

    6: doStuffWithThirdRange,
    7: doStuffWithThirdRange
};

Then instead of the switch:

(dispatcher[myInterval] || doStuffWithAllOthers)();

That works by looking up the function to call on the dispatcher map, defaulting to doStuffWithAllOthers if there's no entry for that specific myInterval value using the curiously-powerful || operator, and then calling it.

You can break that into two lines to make it a bit clearer:

var f = dispatcher[myInterval] || doStuffWithAllOthers;
f();

I've used an object for maximum flexibility. You could define dispatcher like this with your specific example:

var dispatcher = [
    /* 0-2 */
    doStuffWithFirstRange,
    doStuffWithFirstRange,
    doStuffWithFirstRange,

    /* 3-5 */
    doStuffWithSecondRange,
    doStuffWithSecondRange,
    doStuffWithSecondRange,

    /* 6-7 */
    doStuffWithThirdRange,
    doStuffWithThirdRange
];

...but if the values aren't contiguous numbers, it's much clearer to use an object instead.

Carbazole answered 17/6, 2013 at 11:1 Comment(0)
P
22

The ranges in this example are pretty small, but here's how one can handle larger ranges, per the JavaScript MDN Docs:

// The value we'll be evaluating:
let code = 100;

// Matches for any case where the expression === `true`:
switch (true) {
  case code <= 64:
    return "Your number is 64 or less!";
  case code >= 65 && code <= 90:
    return "Your number is in the range of 65-90!";
  case code >= 97 && code <= 122:
    return "Your number is in the range of 97-122!";
  case code >= 123:
    return "Your number is 123 or greater!";
  default:
    break;
}

I know that this style was already shown by T.J. Crowder via Use case with Expressions, but I just wanted to show another example of how to utilize this same method. I just did this and had thought maybe another example might help someone, as I was still a little confused after reading other replies.

Puritanical answered 25/2, 2018 at 1:26 Comment(2)
no need to break when returning.Leader
@Leader thanks for catching that. Apparently my brain wasn't working right that day, much appreciated and fixed. ;PPuritanical
S
7

Is this maybe what you need?

switch(myInterval){

    case 0:
    case 1:
    case 2:
        //doStuff();
        break;

    case 3:
    case 4:
    case 5:
    case 6:
        //doStuff();
        break;

    case 6:
    case 7:
        //doStuff();
        break;

    default:
        //doStuff();
}

If you know the range is going to be very high(for example 0-100) you can also do this, which is surely easier, cleaner and simpler:

if (myInterval >= 0 && myInterval <= 20) {
    //doStuff();
} else if (myInterval > 20 && myInterval <= 60) {
    //doStuff();
} else if (myInterval > 60 && myInterval <= 70) {
    //doStuff();
} else /* it is greater than 70 */ {
    //doStuff();
}
Slug answered 17/6, 2013 at 10:50 Comment(0)
P
4

If your ranges are the same and start from 0 you can do some math.

doStuffWithRange(Math.floor(myInterval/range));

For example, if you want RED, GREEN, and BLUE to the map like your example:

  • Range 0-2 maps to RED
  • Range 3-6 maps to GREEN
  • Range 7-8 maps to BLUE

You can write:

function colorInterval(n, max) {
     var colors = ["RED", "GREEN", "BLUE"];
     var range = max/colors.length
     return colors[Math.floor(n/range)];
 }

//You get 3 of RED, 3 of GREEN, 2 of BLUE
for (var i=0; i<8; i++) {
    console.log(colorInterval(i, 8));
} 

Note that the last range in the example is 2, not 3 and this still works as long as the previous ranges are the same.

Permanence answered 13/5, 2016 at 19:6 Comment(1)
While this solution isn't that flexible (ranges have to be the same), it's still an interesting idea. Nice!Engender
L
2

To add a bit of diversity to the excellent answers already posted, especially as the intervals starts with 0, here is a solution with findIndex (Yeah ES6):

const range = [0, 2, 6, 7];
const randeIndex = range.findIndex(threshold => myInterval <= threshold);
switch (rangeIndex) {
  case 1:
    //doStuffWithFirstRange();
    break;

  case 2:
    //doStuffWithSecondRange();
    break;

  case 3:
    //doStuffWithThirdRange();
    break;
  default:
  //doStuffWithAllOthers();
}

Because the range array is ordered, findIndex will match the first one. Depending on how you name your ranges, stating from 0 or 1, you may need to remove the first 0 in range.

Lamed answered 18/7, 2019 at 6:31 Comment(1)
Good idea, but writing the findIndex function parameter like that makes it unclear what's going on.Suspensoid
P
-2

Use case statement with defined string or value or use "if else if", in case range is higher

Publea answered 17/6, 2013 at 10:52 Comment(1)
This should've been posted as a comment.Czechoslovak
J
-3

int levelNumber = YOUR_VALUE FROM

NSString* strMessage;

switch (levelNumber) {
    case 1...10:
    {
        // Do something...
        break;
    }
    case 11...20:
    {
        // Do something...
        break;
    }
    case 21...30:
    {
        // Do something...
        break;
    }
    case 31...40:
    {
        // Do something...
        break;
    }
    default:
        break;
}

Refer: https://www.codingexplorer.com/loops-switch-statements-ranges-swift/

Jumper answered 19/5, 2016 at 10:46 Comment(4)
I tried this solution but receive an error with both ... and .. separating the values of the range. I don't believe the syntax is valid, as convenient as it would be...Puritanical
this is not a valid syntaxAimless
Updated syntex, there were extra space between ... and number. Now changedJumper
This is for Swift; the question is for JavaScript.Timoteo

© 2022 - 2024 — McMap. All rights reserved.