การใช้คำสั่ง switch กับช่วงของค่าในแต่ละกรณี?


94

ใน Java เป็นไปได้ไหมที่จะเขียนคำสั่ง switch โดยที่แต่ละกรณีมีมากกว่าหนึ่งค่า ตัวอย่างเช่น (แม้ว่ารหัสต่อไปนี้จะไม่ทำงานอย่างชัดเจน):

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

ฉันคิดว่าสิ่งนี้สามารถทำได้ใน Objective C มีสิ่งที่คล้ายกันใน Java หรือไม่? หรือฉันควรใช้เพียงif, else ifงบแทน?


มีส่วนขยายใน C ธรรมดาที่อนุญาตให้ทำเช่นนี้
arshajii

ในกรณีนี้อาจif/elseเป็นทางออกที่ดีกว่า
Eric Wang

คำตอบ:


100

Java ไม่มีอะไรในประเภทนั้น ทำไมไม่ทำสิ่งต่อไปนี้

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
วิธีนี้ใช้งานได้ดีและเรียบง่าย นอกจากนี้หากคุณต้องการเลือกหมายเลขที่ไม่อยู่ในช่วงสิ่งที่คุณต้องการคือ if (! isBetween ... , good job.
a54studio

1
@missingfaktor ฉันได้วิพากษ์วิจารณ์คำตอบของคุณเล็กน้อย ดังนั้นคุณอาจต้องการตอบกลับบางอย่าง +1 แม้ว่า
Alexander Malakhov

@MCEmperor โปรดอย่าแก้ไขคำตอบของฉันด้วยค่ากำหนดการจัดรูปแบบส่วนตัวของคุณ นั่นไม่ใช่การแก้ไขที่มีประโยชน์
missingfaktor

@missingfaktor ขออภัย แต่การแก้ไขนั้นได้รับการอนุมัติเมื่อนานมาแล้ว ฉันจำไม่ได้ว่าฉันเคยทำแบบนั้นมาก่อน
MC Emperor

77

สิ่งที่ใกล้เคียงที่สุดที่คุณจะได้รับจากพฤติกรรมแบบนั้นด้วยswitchข้อความคือ

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

ใช้ifคำสั่ง


30

ทางเลือกอื่นคือการใช้การคำนวณทางคณิตศาสตร์โดยการหารเช่น:

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

แต่อย่างที่คุณเห็นสามารถใช้ได้ก็ต่อเมื่อช่วงได้รับการแก้ไขในแต่ละกรณี


6
ใช้งานได้ดีกับรหัสสถานะ http หารด้วย 100
Stefan

14

ฉันไม่คิดว่าคุณจะทำได้ใน Java ทางออกที่ดีที่สุดคือเพียงใส่รหัสในกรณีสุดท้ายของช่วง

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:
     //
}

11

ฉันรู้ว่าโพสต์นี้เก่า แต่ฉันเชื่อว่าคำตอบนี้สมควรได้รับการยอมรับ ไม่จำเป็นต้องหลีกเลี่ยงคำสั่งสวิตช์ สิ่งนี้สามารถทำได้ใน java แต่ใช้คำสั่ง switch ไม่ใช่กรณี มันเกี่ยวข้องกับการใช้ตัวดำเนินการ ternary

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
ทางออกที่ดี! ด้วย Java 7 และสูงกว่าคุณยังสามารถสลับบน String ดังนั้นกรณีของคุณมากยิ่งขึ้น-เอกสารด้วยตนเองเช่นนั้นswitch ((1 <= num && num <= 5 ) ? "1 .. 5" : ... case "1 .. 5":
Daniel Widdis

@DanielWiddis: ฉันขอแนะนำให้ใช้ enum แทนสตริงเพื่อให้แน่ใจว่าสอดคล้องกัน
nmatt

@nmatt โดยทั่วไปเห็นด้วย ฉันพยายามอนุญาตให้ใช้ไวยากรณ์สไตล์ "1 .. 5"
Daniel Widdis

2
@DanielWiddis: แน่นอนเป็นสิ่งที่ดี; ฉันจะตั้งชื่อค่าคงที่ enum เช่น FROM_1_TO_5 โดยปกติแล้วช่วงจะมีความหมายบางอย่างและในกรณีนี้ค่าคงที่ enum สามารถตั้งชื่อตามความหมายของช่วงได้
nmatt

1
ฉันคิดว่าเราสามารถตกลงกันได้ว่าตัวเลือกใดดีกว่า 0, 1 หรือ 2
Daniel Widdis

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"); 

6

หรือคุณสามารถใช้เคสเดี่ยวของคุณตามที่ต้องการและใช้เคสเริ่มต้นของคุณเพื่อระบุคำแนะนำช่วงเป็น:

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

นี่คือสิ่งที่ฉันทำเสมอ แต่ยังเพิ่มความคิดเห็นในระหว่างกรณีเช่น: // 10-15 ดูค่าเริ่มต้นด้านล่าง
Perdi Estaquel

5

ลองใช้วิธีนี้หากคุณต้องใช้สวิตช์

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

ขอคำอธิบายด้วยได้ไหม .. ?
user1140237

ช่วงฟังก์ชันจะส่งคืนค่าบางส่วนตามอาร์กิวเมนต์อินพุตดังนั้นการตรวจจับ "ช่วงของค่า" จึงสามารถทำได้ที่นี่ควบคู่ไปกับประโยคกรณีสวิตช์
zl9394

สิ่งนี้ใช้ได้กับกรณีการใช้งานของฉันฉันมีตัวแปร int 2 ตัวและฉันต้องการตรวจสอบว่า 2 ตัวแปรอยู่ในช่วงเดียวกันเช่น (10-20), (20-30), .... เช่นนี้
Sameer Kazi

ฉันขอแนะนำให้ใช้ enum แทนค่า int เวทย์มนตร์
nmatt

4

ไม่คุณทำอย่างนั้นไม่ได้ สิ่งที่ดีที่สุดที่คุณสามารถทำได้คือ

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

4

นี่คือวิธีที่สวยงามและเรียบง่ายที่จะไป

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

อธิบายเรื่องนี้ได้ไหม ?? - ฉันได้รับ 'mini ifs' แต่นอกเหนือจาก idk นั้น
Kamin Pallaghy

@Tunaki นี่เป็นอีกif..elseifทางเลือกหนึ่งที่ใช้ใน cascade the ternary operator ( condition ? statementIfTrue : statementIfFalse)
Williem

3

เป็นไปได้ที่จะจัดกลุ่มเงื่อนไขต่างๆในcaseคำสั่งเดียวกันโดยใช้กลไกการตกผ่านที่อนุญาตโดยคำสั่งสวิตช์ซึ่งกล่าวถึงในบทช่วยสอน Javaและระบุไว้อย่างสมบูรณ์ในส่วน§14.11 งบสวิทช์ของJava Language ข้อกำหนด

ข้อมูลโค้ดต่อไปนี้นำมาจากตัวอย่างในบทช่วยสอนโดยจะคำนวณจำนวนวันในแต่ละเดือน (นับจากเดือนที่ 1 ถึงเดือน 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;
}

อย่างที่คุณเห็นสำหรับการครอบคลุมช่วงของค่าในcaseคำสั่งเดียวทางเลือกเดียวคือการแสดงรายการค่าที่เป็นไปได้แต่ละค่าทีละค่า ตัวอย่างเพิ่มเติมนี่คือวิธีใช้ pseudocode ในคำถาม:

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

คุณสามารถใช้enumเพื่อแสดงช่วงของคุณ

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

ได้รับการสนับสนุนเป็นของ Java 12. ตรวจสอบJEP 354 ไม่มี "ช่วง" ที่เป็นไปได้ที่นี่ แต่ก็มีประโยชน์เช่นกัน

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

คุณควรจะใช้สิ่งนั้นใน ints ได้เช่นกัน โปรดสังเกตว่าคำสั่ง switch ของคุณจะต้องครบถ้วนสมบูรณ์ (โดยใช้defaultคำสำคัญหรือใช้ค่าที่เป็นไปได้ทั้งหมดในคำสั่ง case)


2

คำตอบของ @missingfaktor นั้นถูกต้อง แต่ค่อนข้างซับซ้อนเกินไป โค้ดมีรายละเอียดมากกว่า (อย่างน้อยสำหรับช่วงเวลาต่อเนื่อง) ก็อาจเป็นได้และต้องการโอเวอร์โหลด / ร่ายและ / หรือการกำหนดพารามิเตอร์สำหรับ long, float, Integer เป็นต้น

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
ขออภัยสำหรับการตอบกลับช้าฉันไม่สามารถติดตามคำตอบของ SO ได้ในเร็ว ๆ นี้ ฉันจะตอบกลับคำวิจารณ์ของคุณทีละคน 1. โค้ดมีรายละเอียดมากขึ้นเล็กน้อยใช่และยังทำการคำนวณซ้ำซ้อน แต่ IMO นั้นช่วยให้เกิดความชัดเจนในกรณีนี้ ในรหัสของคุณเราต้องจำกรณีก่อนหน้านี้เมื่อตกบันได
missingfaktor

2
สำหรับการต้องการโอเวอร์โหลดและการร่ายนั่นไม่ใช่ IMO สำหรับการวิจารณ์ที่ถูกต้อง Java ไม่มีวิธีที่สมเหตุสมผลในการแยกประเภทตัวเลขกล่าวถึงข้อ จำกัด ของ Java มากกว่าวิธีการนี้ คุณอาจต้องการสำรวจNumประเภทคลาสของ Haskell หากคุณต้องการทำความเข้าใจประเด็นนี้ให้ดีขึ้น
missingfaktor

@missingfaktor 1.ฉันเดาว่าเป็นเรื่องของรสนิยม เมื่อจัดการกับช่วงเวลาต่อเนื่องโดยส่วนตัวฉันชอบคิดว่าifs ราวกับว่าฉันค่อยๆไหลออกจากช่วงย่อยที่ต่ำกว่า นอกจากนี้คำนวณซ้ำซ้อนไม่ได้เป็นปัญหาที่ทุกคน แต่การเปรียบเทียบซ้ำซ้อนเป็นบิตกังวล: if (isBetween(x, 1, 4)) {...} else if (isBetween(x, 6, 10))จะได้รับง่ายที่จะทำให้รถที่อยู่ใกล้เคียงออกจากซิงค์เช่นหลังจากการแก้ไข: ยังไงก็ไม่ใช่เรื่องใหญ่
Alexander Malakhov

2.ตกลง - ข้อ จำกัด ของ Java แต่นั่นคือสิ่งที่เราต้องดำเนินการและโค้ดดั้งเดิมของคุณจะซ้ำกันสำหรับประเภทต่างๆ ในกรณีนี้ปัญหาสามารถบรรเทาได้โดยใช้คลาสNumberแม้ว่าแนวทางของ Haskell จะดีกว่า (ไม่เคยเรียนรู้ Haskell มาก่อน แต่มันคล้ายกับ "Concepts Light" ของ C ++ นอกจากนี้ฉันเชื่อว่าคุณหมายถึงRealไม่ใช่Num)
Alexander Malakhov

2

ใช้การNavigableMapใช้งานเช่น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);

ทางออกที่ยอดเยี่ยม! อย่าลืมตรวจสอบค่าว่างโดยใช้if (messages.floorEntry(value)!=null) ว่าคุณใช้ค่าจำนวนเต็มหรือไม่
Ch Vas

1
@ChVas วิธีการตั้งค่าแผนที่ที่นี่floorEntry()จะไม่ย้อนกลับnull(การใส่Integer.MIN_VALUEคีย์มีจุดประสงค์เพื่อป้องกันสิ่งนั้น) แต่ไม่ว่าค่าของคุณจะเป็นประเภทใดคุณจำเป็นต้องตัดสินใจว่าจะจัดการคีย์นอกช่วงที่ถูกต้องอย่างไร
erickson

0

สำหรับหมายเลขอินพุตในช่วง 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

ไม่สนับสนุนพฤติกรรมประเภทนี้ใน Java อย่างไรก็ตามหากคุณมีโปรเจ็กต์ขนาดใหญ่ที่ต้องการสิ่งนี้ให้พิจารณาผสมผสานโค้ด Groovy ในโปรเจ็กต์ของคุณ โค้ด Groovy ถูกคอมไพล์เป็นไบต์โค้ดและสามารถรันด้วย JVM บริษัท ที่ฉันทำงานใช้ Groovy ในการเขียนคลาสบริการและ Java เพื่อเขียนอย่างอื่น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.