Durum değiştirme: Tek bir numara yerine aralık kullanabilir miyim


92

Switch'i kullanmak istiyorum ama birçok vakam var, kısayol var mı? Şimdiye kadar bildiğim ve denediğim tek çözüm şuydu:

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

Umarım yapabileceğim şey şudur:

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
Böyle bir senaryo için if-else kullanabilirsiniz
Satpal

Yanıtlar:


239

Bu soru için oyuna biraz geç kalmıştır, ancak C # 7'de (Visual Studio 2017 / .NET Framework 4.6.2'de varsayılan olarak mevcuttur) sunulan son değişikliklerde , aralık tabanlı geçiş artık switchifadeyle mümkündür .

Misal:

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

Notlar:

  • Parantezler (ve )gerekli değildir whendurumda, ancak karşılaştırma (lar) gelmek için, bu örnekte kullanılmıştır.
  • varyerine de kullanılabilir int. Örneğin: case var n when n >= 100:.

10
Siz benim kahramanımsınız. Bunu bir küfürle vurgulamak istedim, ama değil. :)
Gawie Greef

2
Koşulun (ve )çevresi whengereksizdir. Yani case int n when n >= 100:çalışıyor.
Uwe Keim

6
Hatta varçalışıyor: Yani case var n when n >= 100:.
Uwe Keim

9
@JamesKo Bence temiz ve bir grup if ifadesine kıyasla okunabilirliği artırıyor, özellikle 3-4'ten fazla koşulunuz varsa.
Sach

1
Bir grup if ifadesinden çok daha üstün, çok daha temiz.
John Stok

44

İşte sorun ifadeniz için daha iyi ve zarif bir çözüm.

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

Şimdi koşullu anahtarımızı aramak için

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

Switch / ifElse için alternatif


1
@Akxaya Hala anahtarın C # ile genişletilmesi gerektiğini düşünüyorum, ancak bu harika görünüyor ve gerçekten iyi çalışıyor gibi görünüyor. Bu örneği paylaştığınız için gerçekten minnettarım. Teşekkürler
WonderWorker

Bu, anahtar / durum sorusundaki aralığa net bir cevap değil.
İşaretçi Boş

13
Sözlük, değerleri eklendikleri sırayla saklamaz ve döndürmez. Bu, Microsoft derleyicisiyle birlikte çalışır, ancak çalışmadığı yerde kolayca uyumlu bir derleyici yazabilir. Bunun yerine List <KeyValuePair <Func <int, bool>, Action >> kullanın. Ayrıca veri yapısını oluşturmanın bir maliyeti olduğunu ve bu nedenle muhtemelen statik salt okunur bir üye olması gerektiğini unutmayın.
Nathan Phillips

@PointerNull: Gelecekte başvurmak için yapılan yorumlar yazılmış gerekli kodu için blog ref lütfen
Akxaya

@NathanPhillips: Bu konuyu açtığınız için teşekkürler. somurtkan, IList koleksiyonu da bir alternatif olacaktır. bu sadece List <t> kullanarak karmaşık parametrelerle uyguladığım bir örnekti.
Akxaya

14

Anahtar koşullarınızı kategorize etmek için üçlü operatörleri kullanırdım.

Yani...

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

İş parçacığını tamamlamak için, burada C # 8 ile sözdizimi:

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

Aralıkları belirtmek istiyorsanız:

  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

Bu durumda if-else kullanılmalıdır, ancak yine de herhangi bir nedenle switch ihtiyacı varsa, aşağıdaki gibi yapabilirsiniz, kesinti olmayan ilk durumlar, ilk kesinti ile karşılaşılıncaya kadar yayılacaktır. Önceki cevapların önerdiği gibi eğer-else over switch'i öneririm.

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

Sen olabilir switchbir birlikte onu kullanarak yapı "sap" aralıkları Listsizin sınırların.

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

Bu yaklaşımla aralıklar farklı açıklıklara sahip olabilir.


6

Aralık sabittir:

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

Aksi takdirde:

  if else

3

Bahsedildiği gibi if-else, bir aralığı ele alacağınız bu durumda daha iyi olacaktır:

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

2

.Net'te yalnızca Visual Basic, anahtar deyimlerinde aralıklara izin verir, ancak C #'da bunun için geçerli bir sözdizimi yoktur.

C # 'da özel probleminizi çözerek, onu şu şekilde çözerdim:

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;

}

Bunu daha fazla açıklamak için, bir yüzde değeriniz olduğunu hayal edin.

Probleminizi bir şablon olarak kullanarak, bunun şöyle görünmesini isteyebilirsiniz:

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;

}

Bununla birlikte, C # bu sözdizimine izin vermediğinden, burada C # 'ın izin verdiği bir çözüm var:

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;

}

Alışmak biraz zaman alabilir, ancak bir kez aldığınızda sorun değil.

Şahsen, aralıklara izin vermek için ifadeleri değiştirmekten memnuniyet duyarım.

C # switch ifadelerinin geleceği

Anahtar ifadelerinin nasıl iyileştirilebileceğine dair sahip olduğum bazı fikirler:

Versiyon A

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

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

    default:
    break;

}

Sürüm B

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

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

    default:
    break;

}

1

C / C ++ kullanırsanız, "aralık" sözdizimi yoktur. Yalnızca her "durum" segmentinden sonra tüm değerleri listeleyebilirsiniz. Dil Ada veya Pascal destek aralığı sözdizimi.


0

Her şeyden önce, bahsettiğiniz programlama dilini belirlemelisiniz. İkincisi, switchifadeler, örneğin numaralandırmalar veya önceden tanımlanmış dizeler gibi anahtarlanmış değişkenle ilgili kapalı seçenek kümeleri için uygun şekilde kullanılır. Bu durumda, eski güzel if-elseyapıyı kullanmanızı öneririm .


0

Yoluyla switchdurumunda bu ifadeleri ise iç içe ile impossible.You gidebilir bu.

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

(number >= 1 && number <= 4)Her numarayı kontrol etmek yerine eski güzelliğe ne dersiniz ? 1 ile 120 arasında nasıl yazarsınız ? ;-)
DarkDust

Oh ve ödeme dikkat =vs ==.
DarkDust

-1

Soru C ile ilgiliyse ( söylemediniz), cevap hayırdır , ancak : GCC ve Clang (belki diğerleri) bir aralık sözdizimini destekler , ancak geçerli ISO C değildir :

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

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

Önce ve sonra bir boşluk bıraktığınızdan emin olun ...yoksa bir sözdizimi hatası alırsınız.


Pascal / delphi de bunu yapar. 1..4 vaka numarası: bir şeyler yap; vb.
Kell

Soru C # ile ilgili
SuB

@SuB: Biliyorum. OP sonunda sorunun hangi dille ilgili olduğunu bize söyledikten sonra bu soruya C # etiketini ekledim. Ancak cevap, buraya bir arama motoru aracılığıyla gelenler için hala yararlı olabilir, bu yüzden silmedim.
DarkDust

-1

C # anahtarında, temelde daha sonra ne yapılacağına dair sözlüklerdir. Bir sözlükte bir aralığa bakamayacağınız için, yapabileceğiniz en iyi durum ... Steve Gomez'in sözünü ettiği zaman.


-3

İf-else ifadelerini || operatörler (veya operatör) gibi:

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

Vay canına, bu biraz karmaşık if (number >= 1 && number <= 4) { … } else if (number >= 5 && number <= 9) { … }, sence de öyle değil mi?
DarkDust

Ah tamam evet ... Ehm ama aynı şeyi yapması gereken davalar emredilmemişse '|| operator '...
Lukas Warsitz

Ancak amacı, bir sayının bir aralık içinde olup olmadığını kontrol etmekti, bu nedenle sıra önemli değil ( kontrol edilen aralıklar dışında ).
DarkDust

Bu bir hata değil , çözümünüz yanlış değil, sadece karmaşık ;-)
DarkDust

== true: face_palm: bu varsayılan davranıştır ve == false için operatörü kullanamazsınız
Et7f3XIV
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.