Usando l'istruzione switch con un intervallo di valori in ogni caso?


91

In Java, è possibile scrivere un'istruzione switch in cui ogni caso contiene più di un valore? Ad esempio (anche se chiaramente il codice seguente non funzionerà):

switch (num) {
    case 1 .. 5:
        System.out.println("testing case 1 to 5");
        break;
    case 6 .. 10:
        System.out.println("testing case 6 to 10");
        break;
}

Penso che questo possa essere fatto in Objective C, c'è una cosa simile in Java? O devo solo usare if, else ifdichiarazioni, invece?


Ci sono anche estensioni in C normale che lo consentono.
arshajii

Risposte:


97

Java non ha niente del genere. Perché non fare semplicemente quanto segue?

public static boolean isBetween(int x, int lower, int upper) {
  return lower <= x && x <= upper;
}

if (isBetween(num, 1, 5)) {
  System.out.println("testing case 1 to 5");
} else if (isBetween(num, 6, 10)) {
  System.out.println("testing case 6 to 10");
}

1
Funziona alla grande ed è semplice. Inoltre, se vuoi selezionare numeri non compresi nell'intervallo, tutto ciò di cui hai bisogno è se (! IsBetween ..., good job.
a54studio

1
@missingfaktor Ho criticato un po 'la tua risposta. Quindi, probabilmente vorresti rispondere qualcosa. +1 però.
Alexander Malakhov

@MCEmperor, per favore non modificare la mia risposta con le tue preferenze di formattazione personali. Non è una modifica utile.
missingfaktor

@missingfaktor Sorry. Ma quella modifica è stata approvata molto tempo fa; Non ricordavo nemmeno di averlo mai fatto.
MC Emperor

76

Il più vicino che puoi ottenere a quel tipo di comportamento con le switchdichiarazioni è

switch (num) {
case 1:
case 2:
case 3:
case 4:
case 5:
     System.out.println("1 through 5");
     break;
case 6:
case 7:
case 8:
case 9:
case 10:
     System.out.println("6 through 10");
     break;
}

Usa le ifdichiarazioni.


29

un'altra alternativa è usare l'operazione matematica dividendola, ad esempio:

switch ((int) num/10) {
    case 1:
        System.out.println("10-19");
        break;
    case 2:
        System.out.println("20-29");
        break;
    case 3:
        System.out.println("30-39");
        break;
    case 4:
        System.out.println("40-49");
        break;
    default:
        break;
}

Ma, come puoi vedere, questo può essere utilizzato solo quando l'intervallo è fisso in ogni caso.


6
Funziona bene con i codici di stato http divisi per 100.
Stefan

13

Non penso che tu possa farlo in Java. La cosa migliore è mettere il codice nell'ultimo caso dell'intervallo.

switch (num) {
  case 1: case 2: case 3: case 4: case 5: 
     System.Out.Println("testing case 1 to 5");
     break;
  case 6: case 7: case 8: case 9: case 10:
     System.Out.Println("testing case 6 to 10");
     break;
  default:
     //
}

10
  case 1: case 2: case 3: case 4: case 5: 
         System.out.println("testing case 1 to 5");
         break;
  case 6: case 7: case 8: case 9: case 10:
         System.out.println("testing case 6 to 10");
         break;
  default:
         System.out.println("default"); 

9

So che questo post è vecchio ma credo che questa risposta meriti un riconoscimento. Non è necessario evitare l'istruzione switch. Questo può essere fatto in java ma attraverso l'istruzione switch, non i case. Implica l'utilizzo di operatori ternari.

public class Solution {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int num = Integer.parseInt(sc.nextLine());

        switch ((1 <= num && num <= 5 ) ? 0 :
                (6 <= num && num <= 10) ? 1 : 2) {

            case 0:
                System.out.println("I'm between one and five inclusive.");
                break;
            case 1:
                System.out.println("I'm between 6 and 10 inclusive.");
                break;
            case 2:
                System.out.println("I'm not between one and five or 6 and 10 inclusive.");
                break;
        }
    }
}

1
Bella soluzione! Con Java 7 e versioni successive potresti anche attivare una stringa in modo che i tuoi casi siano ancora più auto-documentanti, ad esempio, switch ((1 <= num && num <= 5 ) ? "1 .. 5" : ...e poi case "1 .. 5":.
Daniel Widdis

@DanielWiddis: suggerirei di utilizzare un'enumerazione anziché le stringhe, per garantire la coerenza.
nmatt

@nmatt Generalmente d'accordo. Stavo cercando di consentire l'uso della sintassi dello stile "1 .. 5".
Daniel Widdis,

2
@DanielWiddis: Certamente una buona cosa; Chiamerei le costanti enum qualcosa come FROM_1_TO_5. Di solito gli intervalli hanno un certo significato, e in tal caso le costanti enum possono essere denominate in base al significato dell'intervallo.
nmatt

1
Penso che possiamo concordare che entrambe le opzioni siano migliori di 0, 1 o 2.
Daniel Widdis

6

Oppure puoi usare i tuoi casi solisti come previsto e usare il tuo caso predefinito per specificare le istruzioni di intervallo come:

switch(n) {
    case 1 : System.out.println("case 1"); break;
    case 4 : System.out.println("case 4"); break;
    case 99 : System.out.println("case 99"); break;
    default :
        if (n >= 10 && n <= 15)
            System.out.println("10-15 range"); 
        else if (n >= 100 && n <= 200)
            System.out.println("100-200 range");
        else
            System.out.println("Your default case");
        break;   
}

Questo è quello che faccio sempre, ma aggiungo anche un commento tra i casi, ad esempio: // 10-15 vedi sotto default
Perdi Estaquel

5

Prova questo se devi usare switch.

public static int range(int num){ 
    if ( 10 < num && num < 20)
        return 1;
    if ( 20 <= num && num < 30)
        return 2;
    return 3;
}

public static final int TEN_TWENTY = 1;
public static final int TWENTY_THIRTY = 2;

public static void main(String[]args){
    int a = 110;
    switch (range(a)){
        case TEN_TWENTY: 
            System.out.println("10-20"); 
            break;
        case TWENTY_THIRTY: 
            System.out.println("20-30"); 
            break;
        default: break;
    }
}

puoi dare spiegazioni anche tu ..?
user1140237

La funzione range restituisce un valore in base all'argomento di input, quindi il rilevamento "range of value" potrebbe essere effettuato qui, insieme alla clausola switch case.
zl9394

Questo ha funzionato per il mio caso d'uso, ho 2 variabili int e voglio verificare che 2 variabili siano nello stesso intervallo come (10-20), (20-30), ... come questo
Sameer Kazi

Suggerirei di utilizzare un enum invece dei valori magic int.
nmatt

4

No, non puoi farlo. Il meglio che puoi fare è quello

case 1:
case 2:
case 3:
case 4:
case 5: 
  System.Out.Println("testing case 1 to 5");
break;

3

È possibile raggruppare più condizioni nella stessa caseistruzione utilizzando il meccanismo di caduta consentito dalle istruzioni switch, è menzionato nel tutorial Java e completamente specificato nella sezione §14.11. L'istruzione switch della specifica del linguaggio Java .

Il seguente frammento di codice è stato preso da un esempio nel tutorial, calcola il numero di giorni in ogni mese (numerati dal mese 1 al mese 12):

switch (month) {
    case 1: case 3: case 5:
    case 7: case 8: case 10:
    case 12:
        numDays = 31;
        break;
    case 4: case 6:
    case 9: case 11:
        numDays = 30;
        break;
    case 2:
        if (((year % 4 == 0) && 
             !(year % 100 == 0))
             || (year % 400 == 0))
            numDays = 29;
        else
            numDays = 28;
        break;
    default:
        System.out.println("Invalid month.");
        break;
}

Come puoi vedere, per coprire un intervallo di valori in una singola caseistruzione l'unica alternativa è elencare ciascuno dei valori possibili individualmente, uno dopo l'altro. Come esempio aggiuntivo, ecco come implementare lo pseudocodice nella domanda:

switch(num) {
    case 1: case 2: case 3: case 4: case 5:
        System.out.println("testing case 1 to 5");
        break;
    case 6: case 7: case 8: case 9: case 10:
        System.out.println("testing case 6 to 10");
        break;
}

3

Potresti usare un enumper rappresentare i tuoi intervalli,

public static enum IntRange {
  ONE_TO_FIVE, SIX_TO_TEN;
  public boolean isInRange(int v) {
    switch (this) {
    case ONE_TO_FIVE:
      return (v >= 1 && v <= 5);
    case SIX_TO_TEN:
      return (v >= 6 && v <= 10);
    }
    return false;
  }

  public static IntRange getValue(int v) {
    if (v >= 1 && v <= 5) {
      return ONE_TO_FIVE;
    } else if (v >= 6 && v <= 10) {
      return SIX_TO_TEN;
    }
    return null;
  }
}

3

Ecco un modo bello e minimalista per andare

(num > 1 && num < 5) ? first_case_method() 
                     : System.out.println("testing case 1 to 5")
                     : (num > 5 && num < 7)  ? System.out.println("testing case 1 to 5") 
                     : (num > 7 && num < 8)  ? System.out.println("testing case 1 to 5") 
                     : (num > 8 && num < 9)  ? System.out.println("testing case 1 to 5") 
                     : ... 
                     : System.out.println("default");

Puoi spiegare questo ?? - Ottengo il "mini se" ma a parte questo idk.
Kamin Pallaghy

@Tunaki questa è if..elseifun'alternativa che utilizza in cascata l'operatore ternario ( condition ? statementIfTrue : statementIfFalse).
Williem

3

È supportato da Java 12. Dai un'occhiata a JEP 354 . Nessuna possibilità di "intervallo" qui, ma può essere utile.

switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);//number of letters
    case TUESDAY                -> System.out.println(7);
    case THURSDAY, SATURDAY     -> System.out.println(8);
    case WEDNESDAY              -> System.out.println(9);
}

Dovresti essere in grado di implementarlo anche sugli int. Si noti che la propria istruzione switch deve essere esaustiva (utilizzando la defaultparola chiave o tutti i valori possibili nelle istruzioni case).


2

La risposta di @missingfaktor è effettivamente corretta ma un po 'troppo complicata. Il codice è più dettagliato (almeno per intervalli continui) di quanto potrebbe essere e richiede sovraccarichi / cast e / o parametrizzazione per long, float, integer ecc.

if (num < 1)
    System.Out.Println("invalid case: " + num); // you should verify that anyway
else if (num <= 5)
    System.Out.Println("1 to 5");
else if (num <= 10)
    System.Out.Println("6 to 10");
else if (num <= 42)
    System.Out.Println("11 to 42");
else    
    System.Out.Println("43 to +infinity");

3
Ci scusiamo per la risposta in ritardo, non sono in grado di tenere il passo con le risposte SO ultimamente. Risponderò alla tua critica una per una. 1. Il codice è un po 'più prolisso, sì, e fa anche dei calcoli ridondanti. Ma questo IMO sta aiutando la chiarezza in questo caso. Nel tuo codice, devi ricordare i casi precedenti mentre cadi attraverso la scala.
missingfaktor

2
Per quanto riguarda la richiesta di sovraccarichi e cast, non è una critica valida IMO. Che Java non abbia un modo sensato di astrarre sui tipi numerici dice sui limiti di Java, più che su questo approccio. Potresti voler esplorare la Numclasse di tipo di Haskell se desideri capire meglio questo punto.
missingfaktor

@missingfaktor 1. Immagino sia una questione di gusti. Quando ho a che fare con intervalli continui, personalmente mi piace pensare a ifs come se stessi gradualmente estinguendo il subrange inferiore. Inoltre, un calcolo ridondante non è un problema a tutti, ma il confronto ridondante è un po 'preoccupante: si diventa più semplice fare paragoni adiacenti fuori sincrono, ad esempio, dopo un po' di modifica: if (isBetween(x, 1, 4)) {...} else if (isBetween(x, 6, 10)). Comunque, non è un grosso problema.
Alexander Malakhov

2. Concordato - Limitazione di Java, ma è quello con cui dobbiamo lavorare e il tuo codice originale verrà duplicato per vari tipi. In questo caso particolare un problema può essere mitigato usando la classe Number , sebbene l'approccio di Haskell sia migliore (non è mai arrivato ad imparare veramente Haskell, ma assomiglia a "Concepts Light" di C ++. Inoltre, credo che tu intendessi Real, no Num).
Alexander Malakhov

2

Usa NavigableMapun'implementazione, come TreeMap.

/* Setup */
NavigableMap<Integer, Optional<String>> messages = new TreeMap<>();
messages.put(Integer.MIN_VALUE, Optional.empty());
messages.put(1, Optional.of("testing case 1 to 5"));
messages.put(6, Optional.of("testing case 6 to 10"));
messages.put(11, Optional.empty());

/* Use */
messages.floorEntry(3).getValue().ifPresent(System.out::println);

Ottima soluzione! non dimenticare di verificare la presenza di null utilizzando if (messages.floorEntry(value)!=null) se utilizzi un valore Integer
Ch Vas

1
@ChVas Il modo in cui la mappa è impostata qui, floorEntry()non tornerà mai null(l'inserimento della Integer.MIN_VALUEchiave ha lo scopo di impedirlo). Tuttavia, indipendentemente dal tipo di valore, è necessario decidere come gestire le chiavi al di fuori dell'intervallo valido.
erickson

0

Per il numero di input nell'intervallo 0..100

int n1 = 75; // input value
String res; int n=0; 
int[] a ={0,20,35,55,70,85,101};

for(; n1>=a[n]; n++);
switch(6-n+1) {
  case 1: res="A"; break;
  case 2: res="B"; break;
  case 3: res="C"; break;
  case 4: res="D"; break;
  case 5: res="E"; break;
  default:res="F";
}
System.out.println(res);

0

Questo tipo di comportamento non è supportato in Java. Tuttavia, se hai un progetto di grandi dimensioni che ne ha bisogno, considera la possibilità di incorporare codice Groovy nel tuo progetto. Il codice Groovy viene compilato in byte code e può essere eseguito con JVM. L'azienda per cui lavoro utilizza Groovy per scrivere classi di servizi e Java per scrivere tutto il resto.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.