เปลี่ยนกรณี: ฉันสามารถใช้ช่วงแทนตัวเลขเดียวได้ไหม


92

ฉันต้องการใช้สวิตช์ แต่ฉันมีหลายกรณีมีทางลัดหรือไม่? จนถึงตอนนี้ทางออกเดียวที่ฉันรู้และลองคือ:

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

สิ่งที่ฉันหวังว่าจะทำได้มีดังนี้:

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

1
คุณสามารถใช้ if-else สำหรับสถานการณ์ดังกล่าว
เสาร์ที่

คำตอบ:


239

เกมช้าไปหน่อยสำหรับคำถามนี้ แต่ในการเปลี่ยนแปลงล่าสุดที่นำมาใช้ใน C # 7 (พร้อมใช้งานตามค่าเริ่มต้นใน Visual Studio 2017 / .NET Framework 4.6.2) ตอนนี้การสลับตามช่วงสามารถทำได้ด้วยswitchคำสั่ง

ตัวอย่าง:

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

หมายเหตุ:

  • วงเล็บ(และ)ไม่จำเป็นในwhenเงื่อนไข แต่จะใช้ในตัวอย่างนี้เพื่อเน้นการเปรียบเทียบ
  • varอาจใช้แทนint. ตัวอย่างเช่น: case var n when n >= 100:.

10
คุณชายเป็นฮีโร่ของฉัน ฉันต้องการเน้นสิ่งนี้ด้วยคำสบถ แต่ไม่ใช่ :)
Gawie Greef

2
โดยไม่จำเป็น(และสภาพ)รอบ ๆ whenคือcase int n when n >= 100:ยังใช้งานได้
Uwe Keim

6
แม้varไม่ทำงาน: case var n when n >= 100:Ie
Uwe Keim

9
@JamesKo ฉันคิดว่ามันสะอาดและช่วยให้อ่านง่ายขึ้นเมื่อเทียบกับคำสั่ง if มากมายโดยเฉพาะอย่างยิ่งถ้าคุณมีเงื่อนไขมากกว่า 3-4 ข้อ
Sach

1
เหนือกว่างบ if มากมายมันสะอาดกว่ามาก
John Stock

44

นี่คือทางออกที่ดีกว่าและสวยงามสำหรับคำชี้แจงปัญหาของคุณ

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

ตอนนี้เพื่อเรียกสวิตช์ตามเงื่อนไขของเรา

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

ทางเลือกสำหรับ Switch / ifElse


1
@Akxaya ฉันยังคิดว่าควรขยายสวิตช์ใน C # แต่มันดูดีมากและดูเหมือนว่าจะทำงานได้ดีจริงๆ ขอบคุณจริงๆที่คุณแบ่งปันตัวอย่างนี้ ขอบคุณ
WonderWorker

นี่ไม่ใช่คำตอบที่ชัดเจนสำหรับคำถามเกี่ยวกับช่วงในสวิตช์ / กรณี
Pointer Null

13
พจนานุกรมไม่ได้จัดเก็บและส่งคืนค่าตามลำดับที่เพิ่มเข้ามาสิ่งนี้เกิดขึ้นได้กับคอมไพเลอร์ของ Microsoft แต่สามารถเขียนคอมไพเลอร์ที่สอดคล้องกันได้อย่างง่ายดายโดยที่มันไม่ทำงาน ใช้รายการ <KeyValuePair <Func <int, bool>, Action >> แทน โปรดทราบว่ามีค่าใช้จ่ายในการสร้างโครงสร้างข้อมูลดังนั้นจึงควรเป็นสมาชิกแบบอ่านอย่างเดียวแบบคงที่
Nathan Phillips

@PointerNull: โปรดอ้างอิงบล็อกสำหรับรหัสที่จำเป็นซึ่งเขียนไว้ในความคิดเห็นเพื่อใช้อ้างอิงในอนาคต
Akxaya

@NathanPhillips: ขอบคุณที่นำเรื่องนี้ขึ้นมา แน่นอนคอลเลกชัน IList ก็เป็นอีกทางเลือกหนึ่งเช่นกัน นี่เป็นเพียงตัวอย่างที่ฉันใช้กับพารามิเตอร์ที่ซับซ้อนโดยใช้ List <t>
Akxaya

14

ฉันจะใช้ตัวดำเนินการ ternary เพื่อจัดหมวดหมู่เงื่อนไขการสลับของคุณ

ดังนั้น...

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

13

เพื่อให้เธรดสมบูรณ์นี่คือไวยากรณ์ที่มี 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
  };

หากคุณต้องการระบุช่วง:

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

8

ควรใช้ if-else ในกรณีนั้น แต่หากยังจำเป็นต้องใช้สวิตช์ไม่ว่าด้วยเหตุผลใดก็ตามคุณสามารถทำได้ดังต่อไปนี้กรณีแรกที่ไม่มีการหยุดพักจะเผยแพร่จนกว่าจะพบการหยุดพักครั้งแรก ตามที่คำตอบก่อนหน้านี้แนะนำฉันขอแนะนำ 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;
        }

8

คุณสามารถswitchสร้างช่วง "ที่จับ" ได้โดยใช้ร่วมกับListขอบเขตของคุณ

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

ด้วยช่วงแนวทางนี้อาจมีช่วงที่แตกต่างกัน


6

ช่วงเวลาคงที่:

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

มิฉะนั้น:

  if else

3

ตามที่กล่าวไว้if-elseจะดีกว่าในกรณีนี้ซึ่งคุณจะจัดการช่วง:

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

2

ใน. Net เท่านั้น Visual Basic อนุญาตช่วงในคำสั่ง switch แต่ใน C # ไม่มีไวยากรณ์ที่ถูกต้องสำหรับสิ่งนี้

การแก้ไขปัญหาเฉพาะของคุณใน C # ฉันจะแก้ปัญหานี้:

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;

}

เพื่ออธิบายสิ่งนี้เพิ่มเติมให้จินตนาการว่าคุณมีค่าเปอร์เซ็นต์

การใช้ปัญหาของคุณเป็นเทมเพลตคุณอาจต้องการให้สิ่งนี้มีลักษณะดังนี้:

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;

}

อย่างไรก็ตามเนื่องจาก C # ไม่อนุญาตให้ใช้ไวยากรณ์นั้นนี่คือวิธีแก้ปัญหาที่ C # อนุญาต:

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;

}

อาจใช้เวลาเล็กน้อยในการทำความคุ้นเคย แต่เมื่อคุณเข้าใจแล้ว

โดยส่วนตัวฉันยินดีต้อนรับคำสั่ง switch เพื่ออนุญาตช่วง

อนาคตของงบสวิตช์ C #

นี่คือแนวคิดบางส่วนที่ฉันมีเกี่ยวกับวิธีปรับปรุงคำสั่ง switch:

เวอร์ชัน A

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

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

    default:
    break;

}

เวอร์ชัน B

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

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

    default:
    break;

}

1

หากคุณใช้ C / C ++ จะไม่มีไวยากรณ์ "range" คุณสามารถแสดงรายการค่าทั้งหมดหลังจากแต่ละกลุ่ม "case" เท่านั้น ไวยากรณ์ช่วงการสนับสนุนภาษา Ada หรือ Pascal


0

ก่อนอื่นคุณควรระบุภาษาโปรแกรมที่คุณอ้างถึง ประการที่สองswitchคำสั่งถูกใช้อย่างเหมาะสมสำหรับชุดตัวเลือกปิดที่เกี่ยวข้องกับตัวแปรที่สลับเช่นการแจงนับหรือสตริงที่กำหนดไว้ล่วงหน้า สำหรับกรณีนี้ผมขอแนะนำให้ใช้if-elseโครงสร้างเก่าที่ดี


0

ในswitchกรณีที่เป็นไปไม่ได้คุณสามารถใช้คำสั่ง if ซ้อนกันได้

if(number>=1 && number<=4){
//Do something
}else if(number>=5 && number<=9){
//Do something
}

สิ่งที่ดีเก่า(number >= 1 && number <= 4)แทนที่จะตรวจสอบแต่ละหมายเลข? คุณจะเขียนอย่างไรระหว่าง 1 ถึง 120 ? ;-)
DarkDust

Oh, และใส่ใจกับเทียบกับ= ==
DarkDust

-1

หากคำถามเกี่ยวกับ C (คุณไม่ได้พูด) คำตอบคือไม่ แต่ : GCC และ Clang (อาจจะเป็นอื่น ๆ ) รองรับไวยากรณ์ช่วงแต่ไม่ใช่ ISO C ที่ถูกต้อง:

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

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

อย่าลืมเว้นวรรคก่อนและหลัง...มิฉะนั้นคุณจะได้รับข้อผิดพลาดทางไวยากรณ์


Pascal / delphi ก็ทำเช่นนี้เช่นกัน กรณีที่ 1..4: ทำบางสิ่ง; ฯลฯ
Kell

คำถามเกี่ยวกับ C #
SuB

@SuB: ฉันรู้ ฉันเพิ่มแท็ก C # ในคำถามนี้หลังจากที่ OP บอกเราในที่สุดว่าคำถามนั้นเกี่ยวกับภาษาใด แต่คำตอบอาจยังมีประโยชน์สำหรับผู้ที่มาที่นี่ผ่านทางเครื่องมือค้นหาซึ่งเป็นสาเหตุที่ฉันไม่ได้ลบทิ้ง
DarkDust

-1

ในกรณีสวิตช์ C # เป็นพจนานุกรมโดยทั่วไปเกี่ยวกับสิ่งที่ต้องทำต่อไป เนื่องจากคุณไม่สามารถค้นหาช่วงในพจนานุกรมได้สิ่งที่ดีที่สุดที่คุณสามารถทำได้คือในกรณีนี้ ... เมื่อข้อความที่สตีฟโกเมซกล่าวถึง


-3

คุณสามารถใช้คำสั่ง if-else กับ || ตัวดำเนินการ (หรือตัวดำเนินการ) เช่น:

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

ว้าวซับซ้อนไปหน่อยสำหรับบางอย่างif (number >= 1 && number <= 4) { … } else if (number >= 5 && number <= 9) { … }คุณไม่คิดเหรอ
DarkDust

อ๋อใช่แล้ว ... เอิ่ม แต่ถ้ากรณีที่ควรจะทำในสิ่งเดียวกันไม่ได้รับคำสั่งคุณต้องใช้ '|| ผู้ดำเนินการ '...
Lukas Warsitz

แต่ประเด็นของเขาคือการตรวจสอบว่าตัวเลขอยู่ในช่วงหรือไม่ดังนั้นลำดับจึงไม่สำคัญ (ยกเว้นช่วงที่ตรวจสอบ)
DarkDust

ไม่ใช่ความผิดวิธีการแก้ปัญหาของคุณไม่ผิดซับซ้อนแค่นั้นเอง ;-)
DarkDust

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