Cambiar caso: ¿puedo usar un rango en lugar de un número?

86

Quiero usar el interruptor, pero tengo muchos casos, ¿hay algún atajo? Hasta ahora, la única solución que conozco y probé es:

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

Lo que espero poder hacer es algo como:

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;
}
usuario3022162
fuente
1
Puede usar if-else para tal escenario
sábado

Respuestas:

226

Un poco tarde para el juego para esta pregunta, pero en los cambios recientes introducidos en C # 7 (disponible de forma predeterminada en Visual Studio 2017 / .NET Framework 4.6.2), el cambio basado en rango ahora es posible con la switchdeclaración.

Ejemplo:

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

Notas:

  • Los paréntesis (y )no son obligatorios en la whencondición, pero se utilizan en este ejemplo para resaltar la (s) comparación (es).
  • vartambién se puede utilizar en lugar de int. Por ejemplo: case var n when n >= 100:.
Steve Gómez
fuente
10
Usted señor, es mi héroe. Quería enfatizar esto con alguna palabrota, pero no. :)
Gawie Greef
2
La condición (y sus )alrededores whenson innecesarios. Es decir, case int n when n >= 100:también funciona.
Uwe Keim
6
Incluso varfunciona: es decir case var n when n >= 100:.
Uwe Keim
9
@JamesKo Creo que es limpio y mejora la legibilidad en comparación con un montón de declaraciones if, especialmente si tiene más de 3-4 condiciones.
Sach
1
Muy superior a un montón de declaraciones if, es mucho más limpio.
John Stock
44

Aquí hay una solución mejor y elegante para su planteamiento de problemas.

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

Ahora para llamar a nuestro interruptor condicional

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

Alternativo para Switch / ifElse

Akxaya
fuente
1
@Akxaya Sigo pensando que el cambio debería extenderse en C #, pero se ve fantástico y parece funcionar muy bien. Realmente aprecio que comparta este ejemplo. Gracias
WonderWorker
Esta no es una respuesta clara al rango en la pregunta de cambio / caso.
Puntero nulo
13
El diccionario no almacena ni devuelve valores en el orden en que se agregan. Esto sucede que funciona con el compilador de Microsoft, pero se podría escribir fácilmente un compilador compatible donde no funcionó. En su lugar, utilice List <KeyValuePair <Func <int, bool>, Action >>. También tenga en cuenta que hay un costo para generar la estructura de datos y, por lo tanto, probablemente debería ser un miembro estático de solo lectura.
Nathan Phillips
@PointerNull: consulte el blog para obtener el código necesario escrito en los comentarios para referencia futura
Akxaya
@NathanPhillips: gracias por mencionar esto. La colección IList también sería una alternativa. esto fue solo una muestra que implementé con parámetros complejos usando List <t>.
Akxaya
13

Usaría operadores ternarios para categorizar sus condiciones de cambio.

Entonces...

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;
         }
gráfico divino
fuente
12

Para completar el hilo, aquí está la sintaxis con 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
  };

Si desea especificar los rangos:

  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
fuente
8

If-else debería usarse en ese caso, pero si todavía es necesario cambiar por cualquier motivo, puede hacer lo siguiente, los primeros casos sin interrupción se propagarán hasta que se encuentre la primera interrupción. Como han sugerido las respuestas anteriores, recomiendo el cambio if-else over.

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
fuente
8

Podrías haber switchconstruido rangos de "control" usándolo junto con uno Listde tus límites.

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

Con este enfoque, los rangos pueden tener diferentes intervalos.

usuario3598756
fuente
6

El intervalo es constante:

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

De otra manera:

  if else
benba
fuente
3

Como se mencionó if-else, sería mejor en este caso, donde manejará un rango:

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

En .Net, solo Visual Basic permite rangos en declaraciones de cambio, pero en C # no hay una sintaxis válida para esto.

Abordando su problema específico en C #, lo resolvería así:

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;

}

Para ilustrar esto aún más, imagine que tiene un valor porcentual.

Si usa su problema como plantilla, es posible que desee que se vea así:

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;

}

Sin embargo, dado que C # no permite esa sintaxis, aquí hay una solución que C # sí permite:

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;

}

Puede tomar un poco acostumbrarse, pero está bien una vez que lo consiga.

Personalmente, agradecería cambiar declaraciones para permitir rangos.

El futuro de las declaraciones de cambio de C #

Aquí hay algunas ideas que tuve de cómo se podrían mejorar las declaraciones de cambio:

Versión A

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

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

    default:
    break;

}

Versión B

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

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

    default:
    break;

}
WonderWorker
fuente
1

Si usa C / C ++, no hay sintaxis de "rango". Solo puede enumerar todos los valores después de cada segmento de "caso". Language Ada o Pascal admiten la sintaxis de rango.

SliceSort
fuente
0

En primer lugar, debe especificar el lenguaje de programación al que se refiere. En segundo lugar, las switchdeclaraciones se utilizan correctamente para conjuntos cerrados de opciones con respecto a la variable conmutada, por ejemplo, enumeraciones o cadenas predefinidas. Para este caso, sugeriría usar la buena if-elseestructura antigua .

Andrei Nicusan
fuente
0

A través del switchcaso es imposible Puede utilizar declaraciones if anidadas.

if(number>=1 && number<=4){
//Do something
}else if(number>=5 && number<=9){
//Do something
}
Joke_Sense10
fuente
¿Qué pasa con el viejo en (number >= 1 && number <= 4)lugar de comprobar cada número? ¿Cómo escribirías entre 1 y 120 ? ;-)
DarkDust
Ah, y prestar atención a =frente ==.
DarkDust
-1

Si la pregunta fue sobre C (que no has dicho), entonces la respuesta es no, pero : GCC y Sonido metálico (tal vez otros) soportan una sintaxis de rango , pero es no válido ISO C:

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

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

Asegúrese de tener un espacio antes y después de ...o obtendrá un error de sintaxis.

DarkDust
fuente
Pascal / delphi también hace esto. número de caso de 1..4: hacer algo; etc.
Kell
La pregunta es sobre C #
SuB
@SuB: Lo sé. Agregué la etiqueta C # a esta pregunta después de que OP finalmente nos dijo de qué idioma trata la pregunta. Pero la respuesta aún puede ser útil para las personas que vienen aquí a través de un motor de búsqueda, por lo que no la he eliminado.
DarkDust
-1

En C #, los casos de cambio son básicamente diccionarios sobre qué hacer a continuación. Como no puede buscar un rango en un diccionario, lo mejor que puede hacer es el caso ... cuando la declaración mencionada por Steve Gómez.

user3406087
fuente
-3

Puede usar declaraciones if-else con || operadores (u-operador) como:

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
fuente
Vaya, eso es un poco complicado para algo así if (number >= 1 && number <= 4) { … } else if (number >= 5 && number <= 9) { … }, ¿no crees?
DarkDust
Oh, está bien, sí ... Ehm, pero si los casos que se supone que deben hacer lo mismo no están ordenados, debe usar el '|| operador '...
Lukas Warsitz
Pero su objetivo era verificar si un número está dentro de un rango, por lo que el orden no importa (excepto por los rangos marcados).
DarkDust
No es una falla , su solución no es incorrecta, solo complicada ;-)
DarkDust
== true: face_palm: este es el comportamiento predeterminado y para == false puede usar not operator
Et7f3XIV