147

I want to use switch, but I have many cases, is there any shortcut? So far the only solution I know and tried is:

switch (number)
{
case 1: something; break;
case 2: other thing; break;
...
case 9: .........; break;
}

What I hope I'm able to do is something like:

switch (number)
{
case (1 to 4): do the same for all of them; break;
case (5 to 9): again, same thing for these numbers; break;
}
jarrodwhitley
  • 826
  • 10
  • 29
user3022162
  • 1,499
  • 2
  • 10
  • 4

16 Answers16

365

Original Answer for C# 7

A bit late to the game for this question, but in recent changes introduced in C# 7 (Available by default in Visual Studio 2017/.NET Framework 4.6.2), range-based switching is now possible with the switch statement.

Example:

int i = 63;

switch (i)
{
    case int n when (n >= 100):
        Console.WriteLine($"I am 100 or above: {n}");
        break;

    case int n when (n < 100 && n >= 50 ):
        Console.WriteLine($"I am between 99 and 50: {n}");
        break;

    case int n when (n < 50):
        Console.WriteLine($"I am less than 50: {n}");
        break;
}

Notes:

  • The parentheses ( and ) are not required in the when condition, but are used in this example to highlight the comparison(s).
  • var may also be used in lieu of int. For example: case var n when n >= 100:.

Updated examples for C# 9

switch(myValue)
{
    case <= 0:
        Console.WriteLine("Less than or equal to 0");
        break;
    case > 0 and <= 10:
        Console.WriteLine("More than 0 but less than or equal to 10");
        break;
    default:
        Console.WriteLine("More than 10");
        break;
}

or

var message = myValue switch
{
    <= 0 => "Less than or equal to 0",
    > 0 and <= 10 => "More than 0 but less than or equal to 10",
    _ => "More than 10"
};
Console.WriteLine(message);
Steve
  • 11,596
  • 7
  • 39
  • 53
  • 19
    You sir, are my hero. I wanted to emphasize this with some swear word, but rather not. :) – Gawie Schneider Dec 31 '17 at 12:30
  • 3
    The `(` and `)` around the `when` condition are unnecessary. I.e. `case int n when n >= 100:` also works. – Uwe Keim Jan 07 '18 at 17:44
  • 6
    Even `var` does work: I.e. `case var n when n >= 100:`. – Uwe Keim Jan 07 '18 at 17:48
  • Nice answer. But honestly, how is this better than a bunch of if statements? – James Ko Apr 15 '18 at 18:59
  • 10
    @JamesKo I think it's clean and improves readability compared to a bunch of if statements, particularly if you have more than 3-4 conditions. – Sach Apr 27 '18 at 17:11
  • 2
    Far superior to a bunch of if statements, it's much cleaner. – John Stock Jun 11 '19 at 13:25
  • Question is, is the compiler smart enough to reuse `n` or is the same cast instruction reexecuted for each case? – vc 74 Apr 17 '20 at 07:03
  • 1
    Also works when the values are not continuous, e.g.: `case int n when (new int[] {-7, 2, 3, 4, 18, 100}.Contains(n)):` – Robert Tausig Aug 04 '20 at 12:55
  • @Sach @J Stock. In this example, the switch statement version is more verbose than its equivalent if-else version so improves readability is a tough sell for me. Apart from being more characters, I find this version where `int n` is declared and then referenced without any obvious assignment to be less intuitive and arguably more difficult to read. One advantage aside form personal preference could be the ability (or accepted practice) to use `goto` in a case. The cases, if written without braces, also don't limit the scope of any variable declarations within unlike a multi-line if/else block. – xr280xr Feb 10 '21 at 03:28
52

To complete the thread, here is the syntax with C# 8 and C# 9 :

C# 9 syntax:

var percent = price switch
{
    >= 1000000 => 7f,
    >= 900000 => 7.1f,
    >= 800000 => 7.2f,
    _ => 0f // default value
};

If you want to specify the ranges :

var percent = price switch
{
    >= 1000000 => 7f,
    < 1000000 and >= 900000 => 7.1f,
    < 900000 and >= 800000 => 7.2f,
    _ => 0f // default value
};

C# 8 syntax:

var percent = price switch
{
    var n when n >= 1000000 => 7f,
    var n when n >= 900000 => 7.1f,
    var n when n >= 800000 => 7.2f,
    _ => 0f // default value
};

If you want to specify the ranges :

var percent = price switch
{
    var n when n >= 1000000 => 7f,
    var n when n < 1000000 && n >= 900000 => 7.1f,
    var n when n < 900000 && n >= 800000 => 7.2f,
    _ => 0f // default value
};
Richard Garside
  • 87,839
  • 11
  • 80
  • 93
A.Baudouin
  • 2,855
  • 3
  • 24
  • 28
49

Here is a better and elegant solution for your problem statement.

int mynumbercheck = 1000;
// Your number to be checked
var myswitch = new Dictionary <Func<int,bool>, Action>
            { 
             { x => x < 10 ,    () => //Do this!...  },  
             { x => x < 100 ,    () => //Do this!...  },
             { x => x < 1000 ,    () => //Do this!...  },
             { x => x < 10000 ,   () => //Do this!... } ,
             { x => x < 100000 ,  () => //Do this!... },
             { x => x < 1000000 ,  () => //Do this!... } 
            };

Now to call our conditional switch

   myswitch.First(sw => sw.Key(mynumbercheck)).Value();

Alternate for Switch/ifElse

Matthew Lock
  • 13,144
  • 12
  • 92
  • 130
Akxaya
  • 834
  • 8
  • 6
  • 1
    @Akxaya I still think switch should be extended in C#, but this looks fantastic and seems to work really well. Really appreciate you sharing this example. Thank you – WonderWorker Oct 04 '16 at 10:27
  • This is not clear answer to range in switch/case question. – Pointer Null Oct 06 '16 at 10:31
  • 13
    Dictionary doesn't store and return values in the order that they are added in. This happens to work with the Microsoft compiler, but one could easily write a complient compiler where it didn't work. Instead use List, Action>>. Also be aware that there is a cost to generating the data structure and so it should probably be a static readonly member. – Nathan Phillips Nov 08 '16 at 13:39
  • 1
    @PointerNull : please ref the blog for needed code written in comments for future reference – Akxaya Nov 10 '17 at 19:04
  • @NathanPhillips : thanks for bring this up. surly, IList collection would also be an alternative. this was just a sample I've implemented with complex parameters using List. – Akxaya Nov 10 '17 at 19:09
  • @NathanPhillips: This is not really related to the *compiler*, is it? Rather, it depends on the concrete implementation of the `Dictionary` class in the BCL. – O. R. Mapper Jul 12 '20 at 14:07
  • Correct, it's the BCL implementation of Dictionary rather than the compiler that determines the behaviour. They would normally go together but strictly speaking you could use the Microsoft compiler and your own BCL implementation and still break the code in this example without doing anything wrong. – Nathan Phillips Jul 13 '20 at 09:34
25

I would use ternary operators to categorize your switch conditions.

So...

switch( number > 9 ? "High" :
        number > 5 ? "Mid" :
        number > 1 ? "Low" : "Floor")
        {
              case "High":
                    do the thing;
                    break;
               case "Mid":
                    do the other thing;
                    break;
               case "Low":
                    do something else;
                    break;
               case "Floor":
                    do whatever;
                    break;
         }
graphicdivine
  • 10,937
  • 7
  • 33
  • 59
  • 2
    Elegant! Cool! And epic wordings. Could an enum and its states be used instead of strings for High, Mid, Low and Floor? – Confused Oct 23 '21 at 07:46
  • @Confused I expect you could use an enum. I haven't tested it but I see no reason why not. – graphicdivine Nov 02 '21 at 09:23
  • Cheers, will give a shot soon, building up to it with a bunch of ADSR envelope editing facilities getting built first. The garbage in part ;) – Confused Nov 02 '21 at 09:41
11

If-else should be used in that case, But if there is still a need of switch for any reason, you can do as below, first cases without break will propagate till first break is encountered. As previous answers have suggested I recommend if-else over switch.

switch (number){
            case 1:
            case 2:
            case 3:
            case 4: //do something;
                    break;
            case 5:
            case 6:
            case 7:
            case 8:
            case 9: //Do some other-thing;
                   break;
        }
Gayathri
  • 894
  • 6
  • 19
10

You could have switch construct "handle" ranges by using it in conjunction with a List of your bounds.

List<int> bounds = new List<int>() {int.MinValue, 0, 4, 9, 17, 20, int.MaxValue };

switch (bounds.IndexOf(bounds.Last(x => x < j)))
{
    case 0: // <=0
        break;

    case 1: // >= 1 and <=4
        break;
    case 2: // >= 5 and <=9
        break;
    case 3: // >= 10 and <=17
        break;
    case 4: // >= 18 and <=20
        break;

    case 5: // >20
        break;
}

With this approach ranges can have different spans.

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
user3598756
  • 28,893
  • 4
  • 18
  • 28
8

Interval is constant:

 int range = 5
 int newNumber = number / range;
 switch (newNumber)
 {
      case (0): //number 0 to 4
                break;
      case (1): //number 5 to 9
                break;
      case (2): //number 10 to 14
                break;
      default:  break;
 }

Otherwise:

  if else
benba
  • 821
  • 9
  • 16
5

As mentioned if-else would be better in this case, where you will be handling a range:

if(number >= 1 && number <= 4)
{
   //do something;
}
else if(number >= 5 && number <= 9)
{
   //do something else;
}
henrik
  • 314
  • 2
  • 6
4

In .Net only Visual Basic allows ranges in switch statements, but in C# there is no valid syntax for this.

Tackling your specific problem in C#, I would solve it thus:

if(number >= 1 && number <= 9) // Guard statement
{
    if(number < 5)
    {
        // Case (1 to 4):

        //break;

    }
    else
    {
        // Case (5 to 9):

        //break;

    }

}
else
{
    // Default code goes here

    //break;

}

To illustrate this further, imagine you have a percentage value.

Using your problem as a template, you might wish this to look like:

switch (percentage)
{
    case (0 to 19):
        break;

    case (20 to 39):
        break;

    case (40 to 69):
        break;

    case (70 to 79):
        break;

    case (80 to 100):
        break;

    default:
        break;

}

However, since C# doesn't allow that syntax, here is a solution that C# does allow:

if (percentage >= 0 && percentage <= 100) // Guard statement
{
    if (percentage >= 40)
    {
        if (percentage >= 80)
        {
            // Case (80% to 100%)

            //break;

        }
        else
        {
            if (percentage >= 70)
            {
                // Case (70% to 79%)

                //break;

            }
            else
            {
                // Case (40% to 69%)

                //break;

            }

        }

    }
    else
    {
        if (percentage >= 20)
        {
            // Case (20% to 39%)

            //break;

        }
        else
        {
            // Case (0% to 19%)

            //break;

        }

    }

}
else
{
    // Default code goes here

    //break;

}

It can take a little getting used to, but it's fine once you get it.

Personally, I would welcome switch statements to allow ranges.

The future of C# switch statements

Here are some ideas I had of how switch statements could be improved:

Version A

switch(value)
{
    case (x => x >= 1 && x <= 4):
    break;

    case (x => x >= 5 && x <= 9):
    break;

    default:
    break;

}

Version B

switch(param1, param2, ...)
{
    case (param1 >= 1 && param1 <= 4):
    break;

    case (param1 >= 5 && param1 <= 9 || param2 != param1):
    break;

    default:
    break;

}
WonderWorker
  • 8,539
  • 4
  • 63
  • 74
3

If you use C/C++, there's no "range" syntax. You can only list all values after each "case" segment. Language Ada or Pascal support range syntax.

SliceSort
  • 357
  • 3
  • 5
2

If the range is small you can fall through cases to get to the same point. For example:

int number = 3;
switch (number)
{
    case 1:
    case 2:
    case 3:
    case 4:
        Console.WriteLine("Number is <= 1 <= 4");
        break;
    case 5:
        Console.WriteLine("Number is 5");
        break;
    default:
        Console.WriteLine("Number is anything else");
        break;
}
1

First of all, you should specify the programming language you're referring to. Second, switch statements are properly used for closed sets of options regarding the switched variable, e.g. enumerations or predefined strings. For this case, I would suggest using the good old if-else structure.

Andrei Nicusan
  • 4,555
  • 1
  • 23
  • 36
1

Through switch case it's impossible.You can go with nested if statements.

if(number>=1 && number<=4){
//Do something
}else if(number>=5 && number<=9){
//Do something
}
Joke_Sense10
  • 5,341
  • 2
  • 18
  • 22
1

If the question was about C (you didn't say), then the answer is no, but: GCC and Clang (maybe others) support a range syntax, but it's not valid ISO C:

switch (number) {
    case 1 ... 4:
        // Do something.
        break;

    case 5 ... 9:
        // Do something else.
        break;
}

Be sure to have a space before and after the ... or else you'll get a syntax error.

DarkDust
  • 90,870
  • 19
  • 190
  • 224
  • Pascal/delphi does this too. case number of 1..4 : do something; etc. – Kell Apr 17 '14 at 23:50
  • The question is about C# – SuB Oct 18 '16 at 07:03
  • @SuB: I know. I added the C# tag to this question after OP finally told us which language the question is about. But the answer may still be useful to people who come here via a search engine which is why I haven't deleted it. – DarkDust Oct 18 '16 at 08:47
-1

In C# switch cases are basically dictionaries on what to do next. Since you can't look up a range in a dictionary, the best you can do is the case ... when statement Steve Gomez mentioned.

ejderuby
  • 710
  • 5
  • 21
-3

You can use if-else statements with || operators (or-operator) like:

if(case1 == true || case2 == true || case3 == true)
   {
    Do this!... 
   }
else if(case4 == true || case5 == true || case6 == true)
   {
    Do this!... 
   }
else if(case7 == true || case8 == true || case9 == true)
   {
    Do this!... 
   }
Lukas Warsitz
  • 1,231
  • 1
  • 11
  • 20
  • 1
    Wow, that's a bit complicated for something like `if (number >= 1 && number <= 4) { … } else if (number >= 5 && number <= 9) { … }`, don't you think? – DarkDust Nov 22 '13 at 15:08
  • Oh alright yes... Ehm but if the cases that are supposed to do the same thing arent ordered you need to use the '|| operator'... – Lukas Warsitz Nov 22 '13 at 15:11
  • But his point was to check whether a number is within a range, so the order doesn't matter (except for the _ranges_ checked). – DarkDust Nov 22 '13 at 15:12
  • It's not a _fault_, your solution is not wrong, just complicated ;-) – DarkDust Nov 22 '13 at 15:15
  • 1
    == true :face_palm: this is the default behaviour and for == false you can use not operator – Et7f3XIV Mar 11 '19 at 19:08