Schalterfall: Kann ich einen Bereich anstelle einer Zahl verwenden?

86

Ich möchte switch verwenden, habe aber viele Fälle. Gibt es eine Verknüpfung? Bisher ist die einzige Lösung, die ich kenne und ausprobiert habe:

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

Ich hoffe, dass ich dazu in der Lage bin:

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;
}
user3022162
quelle
1
Sie können if-else für ein solches Szenario verwenden
Satpal

Antworten:

226

Etwas spät im Spiel für diese Frage, aber in den letzten Änderungen, die in C # 7 eingeführt wurden (standardmäßig in Visual Studio 2017 / .NET Framework 4.6.2 verfügbar), ist mit der switchAnweisung jetzt eine bereichsbasierte Umschaltung möglich .

Beispiel:

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

Anmerkungen:

  • Die Klammern (und )sind in der whenBedingung nicht erforderlich , werden jedoch in diesem Beispiel verwendet, um die Vergleiche hervorzuheben.
  • varkann auch anstelle von verwendet werden int. Zum Beispiel : case var n when n >= 100:.
Steve Gomez
quelle
10
Sie, mein Herr, sind mein Held. Ich wollte dies mit einem Schimpfwort betonen, aber eher nicht. :)
Gawie Greef
2
Die (und )um den whenZustand sind unnötig. Dh case int n when n >= 100:funktioniert auch.
Uwe Keim
6
Funktioniert sogar var: Dh case var n when n >= 100:.
Uwe Keim
9
@JamesKo Ich denke, es ist sauber und verbessert die Lesbarkeit im Vergleich zu einer Reihe von if-Anweisungen, insbesondere wenn Sie mehr als 3-4 Bedingungen haben.
Sach
1
Es ist einer Reihe von if-Aussagen weit überlegen und viel sauberer.
John Stock
44

Hier ist eine bessere und elegantere Lösung für Ihre Problemstellung.

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

Rufen Sie jetzt unseren bedingten Schalter an

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

Alternative für Switch / ifElse

Akxaya
quelle
1
@Akxaya Ich denke immer noch, dass der Schalter in C # erweitert werden sollte, aber das sieht fantastisch aus und scheint wirklich gut zu funktionieren. Ich schätze es sehr, dass Sie dieses Beispiel teilen. Vielen Dank
WonderWorker
Dies ist keine eindeutige Antwort auf den Bereich in der Schalter- / Fallfrage.
Zeiger Null
13
Dictionary speichert und gibt Werte nicht in der Reihenfolge zurück, in der sie hinzugefügt wurden. Dies funktioniert zufällig mit dem Microsoft-Compiler, aber man könnte leicht einen kompatiblen Compiler schreiben, in dem es nicht funktioniert hat. Verwenden Sie stattdessen List <KeyValuePair <Func <int, bool>, Action >>. Beachten Sie auch, dass die Generierung der Datenstruktur mit Kosten verbunden ist und daher wahrscheinlich ein statisches schreibgeschütztes Element sein sollte.
Nathan Phillips
@PointerNull: Bitte verweisen Sie auf den Blog für den benötigten Code, der in Kommentaren zur späteren Bezugnahme geschrieben wurde
Akxaya
@ NathanPhillips: Danke, dass du das angesprochen hast. Sicherlich wäre die IList-Sammlung auch eine Alternative. Dies war nur ein Beispiel, das ich mit komplexen Parametern mithilfe von List <t> implementiert habe.
Akxaya
13

Ich würde ternäre Operatoren verwenden, um Ihre Switch-Bedingungen zu kategorisieren.

Damit...

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;
         }
Grafikgöttlich
quelle
12

Um den Thread zu vervollständigen, ist hier die Syntax mit C # 8:

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

Wenn Sie die Bereiche angeben möchten:

  var percent2 = 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
  };
A. Baudouin
quelle
8

Wenn-else in diesem Fall verwendet werden sollte. Wenn jedoch aus irgendeinem Grund immer noch ein Wechsel erforderlich ist, können Sie wie folgt vorgehen: Erste Fälle ohne Unterbrechung breiten sich aus, bis die erste Unterbrechung auftritt. Wie in früheren Antworten vorgeschlagen, empfehle ich 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
quelle
8

Sie können switch"Handle" -Bereiche erstellen, indem Sie sie in Verbindung mit einer ListIhrer Grenzen verwenden.

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

Bei diesem Ansatz können Bereiche unterschiedliche Bereiche haben.

user3598756
quelle
6

Das Intervall ist konstant:

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

Andernfalls:

  if else
benba
quelle
3

Wie bereits erwähnt, if-elsewäre es in diesem Fall besser, wenn Sie einen Bereich bearbeiten:

if(number >= 1 && number <= 4)
{
   //do something;
}
else if(number >= 5 && number <= 9)
{
   //do something else;
}
Henrik
quelle
2

In .Net erlaubt nur Visual Basic Bereiche in switch-Anweisungen, in C # gibt es hierfür keine gültige Syntax.

Wenn Sie Ihr spezifisches Problem in C # angehen, würde ich es folgendermaßen lösen:

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;

}

Stellen Sie sich zur weiteren Veranschaulichung vor, Sie hätten einen Prozentwert.

Wenn Sie Ihr Problem als Vorlage verwenden, möchten Sie möglicherweise Folgendes sehen:

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;

}

Da C # diese Syntax jedoch nicht zulässt, ist hier eine Lösung, die C # zulässt:

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;

}

Es kann etwas gewöhnungsbedürftig sein, aber es ist in Ordnung, sobald Sie es bekommen.

Persönlich würde ich switch-Anweisungen begrüßen, um Bereiche zuzulassen.

Die Zukunft der C # -Schalteranweisungen

Hier sind einige Ideen, wie Switch-Anweisungen verbessert werden könnten:

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
quelle
1

Wenn Sie C / C ++ verwenden, gibt es keine "Bereich" -Syntax. Sie können nur alle Werte nach jedem "Fall" -Segment auflisten. Sprache Ada oder Pascal unterstützen die Syntax des Bereichs.

SliceSort
quelle
0

Zunächst sollten Sie die Programmiersprache angeben, auf die Sie sich beziehen. Zweitens werden switchAnweisungen ordnungsgemäß für geschlossene Optionssätze in Bezug auf die geschaltete Variable verwendet, z. B. Aufzählungen oder vordefinierte Zeichenfolgen. Für diesen Fall würde ich vorschlagen, die gute alte if-elseStruktur zu verwenden.

Andrei Nicusan
quelle
0

Durch den switchFall ist es unmöglich. Sie können mit verschachtelten if-Anweisungen gehen.

if(number>=1 && number<=4){
//Do something
}else if(number>=5 && number<=9){
//Do something
}
Joke_Sense10
quelle
Was ist mit gutem Alter, (number >= 1 && number <= 4)anstatt jede Nummer zu überprüfen? Wie würden Sie zwischen 1 und 120 schreiben ? ;-)
DarkDust
Ach ja, und achten Sie auf =vs. ==.
DarkDust
-1

Wenn es sich bei der Frage um C handelte (Sie haben es nicht gesagt), lautet die Antwort nein, aber : GCC und Clang (möglicherweise andere) unterstützen eine Bereichssyntax , aber sie ist nicht gültig. ISO C:

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

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

Stellen Sie sicher, dass vor und nach dem ein Leerzeichen steht. ...Andernfalls wird ein Syntaxfehler angezeigt.

DarkDust
quelle
Pascal / Delphi macht das auch. Fallnummer 1..4: etwas tun; usw.
Kell
Die Frage ist über C #
SuB
@SuB: Ich weiß. Ich habe dieser Frage das C # -Tag hinzugefügt, nachdem OP uns schließlich mitgeteilt hat, um welche Sprache es sich bei der Frage handelt. Aber die Antwort kann für Leute, die über eine Suchmaschine hierher kommen, immer noch nützlich sein, weshalb ich sie nicht gelöscht habe.
DarkDust
-1

In C # -Schaltfällen handelt es sich im Grunde genommen um Wörterbücher, in denen beschrieben wird, was als Nächstes zu tun ist. Da Sie einen Bereich in einem Wörterbuch nicht nachschlagen können, ist das Beste, was Sie tun können, der Fall ... als die Aussage Steve Gomez erwähnte.

user3406087
quelle
-3

Sie können if-else-Anweisungen mit || verwenden Operatoren (oder-Operatoren) wie:

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
quelle
Wow, das ist ein bisschen kompliziert für so etwas if (number >= 1 && number <= 4) { … } else if (number >= 5 && number <= 9) { … }, findest du nicht?
DarkDust
Oh in Ordnung, ja ... Ähm, aber wenn die Fälle, die dasselbe tun sollen, nicht bestellt sind, müssen Sie das '|| verwenden Betreiber '...
Lukas Warsitz
Es ging ihm jedoch darum zu prüfen, ob eine Zahl innerhalb eines Bereichs liegt, sodass die Reihenfolge keine Rolle spielt (mit Ausnahme der überprüften Bereiche ).
DarkDust
Es ist kein Fehler , deine Lösung ist nicht falsch, nur kompliziert ;-)
DarkDust
== true: face_palm: Dies ist das Standardverhalten und für == false können Sie keinen Operator verwenden
Et7f3XIV