Switch deyimlerini mi kullanmalıyım yoksa… zincirler daha mı uzun?


36

Genellikle switch ifadesini duyduğumda, uzun süre yerine geçecek bir yöntem olarak ... başka zincirler çıkardı. Fakat anlaşılan anahtar, switch ifadesini kullandığımda sadece yazacağım koddan daha fazla kod yazıyorum. Tüm çağrılar için tüm değişkenleri aynı kapsamda tutmak gibi başka sorunlarınız da var .

İşte normalde yazdığım akışı gösteren bazı kodlar ( çap sayesinde )

String comment;   // The generated insult.
int which = (int)(Math.random() * 3);  //  Result is 0, 1, or 2.

if (which == 0) {
    comment = "You look so much better than usual.";
} else if (which == 1) {
    comment = "Your work is up to its usual standards.";
} else if (which == 2) {
    comment = "You're quite competent for so little experience.";
} else {
    comment = "Oops -- something is wrong with this code.";
}

Sonra bunu bununla değiştirmemi istiyorlar:

String comment;   // The generated insult.
int which = (int)(Math.random() * 3);  //  Result is 0, 1, or 2.

switch (which) {
    case 0:  
             comment = "You look so much better than usual.";
    break;
    case 1:  
             comment = "Your work is up to its usual standards.";
    break;
    case 2:  
             comment = "You're quite competent for so little experience.";
    break;
    default: 
             comment = "Oops -- something is wrong with this code.";
}

Çok daha garip bir sözdiziminde çok daha fazla kod gibi görünüyor. Ancak switch deyimini kullanmanın gerçekten bir avantajı var mı?


Ugh. Evet, bu kesinlikle daha hantal bir durum, ama sadece C ailesinde, çünkü durum ifadeleri için yazım şekli çok çirkin.
Mason Wheeler


1
Mümkün olduğunda her ikisinden de kaçınmalısınız. Arama hedefi bir işlev veya sınıf olsa bile, bir veri yapısı oluşturmak ve bir arama yapmak çok daha iyidir.
kevin cline

anahtar, en azından .net'te daha hızlıdır. Java'yı bilmiyorum.
Knerd

Bir dava, yöntem ve bir "eğer" sözlüğüne yeniden
yansıtılabilir

Yanıtlar:


57

Bu özel durum için, her iki geliyor bana ifve casefakir seçeneklerdir. Basit bir dizi kullanırdım:

String comments[] = {
    "You look so much better than usual.",
    "Your work is up to its usual standards.",
    "You're quite competent for so little experience."
};

String comment = comments[(int)(Math.random() * 3)];

Bir yan not olarak, genellikle çarpanı kodlamak yerine dizinin boyutuna göre çarpanı hesaplamanız gerekir 3.

Ne zaman için de olur bir kaskad bir durumda / anahtar fark kullanımı iftablolarına (ya da en azından önemli bir fark) olan switchyarı otomatik olarak optimize bir çağlayan ise, sayısı ve değerine yoğunluğuna dayanarak olabilir ififadeler yaprak derleyici çok az seçeneğiniz varsa, ancak kodunuzu yazdığınız şekilde oluşturmak için, bir eşleşme bulana kadar birbiri ardına bir değeri test edin. Sadece üç gerçek durumla, bu pek endişe verici değil, ancak yeterli sayıda olması önemli olabilir.


Bu örnek yalnızca bir örnek BTW idi. Derleyicinin böyle bir optimizasyon yapabildiğini bilmiyordum
TheLQ,

6
@JBRWilkinson. Bu durumda, sınırların dışında kalan değer, yalnızca çok fazla zaman harcamaktan kaçındığım derleyici bir hatayla mümkündür (sonucu sınamak için kodumdaki hata, kod oluşturmada olduğu gibi). Sınırların dışında bir değerin gerçek bir sorun olduğu bir durumda (örneğin, endeks başka bir koddan alındı) Önce sınırları kontrol ettim ve sadece kontrolden sonra bir indeks olarak kullandım.
Jerry Coffin

4
Bence bu cevap örnekle ilgili çok spesifik, soru bundan daha
jenerikken

3
@Kbenben: Bana bütün cevabı okuma zahmetinde bulunmadığın gibi geliyor. Son paragraf daha geniş sorunları ele almaktadır. Ben bulmak: gerçi bir sorun var çok az ben düşünün ettiği durumları ya bir caseaçıklama ya bir çağlayan ifuygun tablolar. Çoğu zaman, bunlar bir çeşit harita / dizi türü için (vasat) bir ikamedir ve ikincisini doğrudan kullanmaktan daha iyidir.
Jerry Coffin

1
@Titou: derleyici tamamen bağlayıcılı değilse, dizi derleme zamanında bir kez kurulacak ve bundan sonra sadece statik bir yapı kullanacaksınız. Örneğin, bunu C veya C ++ ile yapıyor olsaydınız static const, her zaman var olduğundan emin olmak için bir dizi yapmak isterdiniz (ancak soruda dil verilmedi, bu yüzden de cevapta bir varsayımda bulunmamaya çalıştım.). ).
Jerry Coffin

23

if...else if...Zincirle ilgili sorun, onu okumak için geldiğimde if, programın ne yaptığını anlamak için her koşula bakmam gerektiğidir. Örneğin, şöyle bir şey olabilir:

if (a == 1) {
    // stuff
} else if (a == 2) {
    // stuff
} else if (a == 3) {
    // stuff
} else if (b == 1) {
    // stuff
} else if (b == 2) {
    // stuff
}

(Açıkçası, bunun gibi az sayıda ifade için o kadar da kötü değil)

Her bir ifadeyi okumadan koşul değişkenini yarı yolda değiştirdiğinizi bilmenin hiçbir yolu olmazdı. Ancak, switchsizi yalnızca tek bir koşul değişkeni ile sınırlandırdığından, bir bakışta neler olduğunu görebiliyorum.

Günün sonunda olsa da, ne de switchbir zincir tercih ederim if...else if. Genellikle daha iyi bir çözüm, asıl sorudaki gibi durumlar için bir tür atlama tablosu veya sözlüktür veya polimorfizmdir (eğer diliniz destekliyorsa). Elbette her zaman mümkün değildir, ama switchilk adım olarak kaçan bir çözüm ararım ...


4
polimorfizm, kodu parçalama dezavantajına sahiptir ve tek bir konumda olmasıyla karşılaştırıldığında daha zor anlaşılmasını sağlar. Bu nedenle, bunu değiştirmeden önce biraz tereddüt edebilirsiniz.

Bir atlama tablosu / sözlüğü neden bir anahtardan daha iyidir?
Titou

14
switch (which) {
  case 0: comment = "String 1"; break;
  case 1: comment = "String 2"; break;
  case 2: comment = "String 3"; break;
  default: comment = "Oops"; break;
}

Bu tür bir anahtar kasası yazmanın yukarıdaki yolu oldukça yaygındır. Şalterciye göre şalter çantasını hissetmenin sebebi, vücudunuzun sadece bir satır olması ve şalter çantasına sahip olmanız için ayrıca break deyimine ihtiyacınız oldu. Bu yüzden, anahtar kasası iki kat daha büyüktü. Daha önemli kodlarla birlikte, break ifadesi gövdeye fazla bir şey eklemeyecek. Tek satırlı gövde için, kodu case ifadesiyle aynı satıra yazmak yaygın bir uygulamadır.

Diğerlerinin de belirttiği gibi, bir geçiş davası amacı daha açık bir hale getirir, tek bir değişkenin / ifadenin değerini temel alan bir karar vermek istersiniz. Yorumlarım, tamamen okunaklı bir bakış açısıyla, performansa dayalı değil.


1
Düğmeyi bir yönteme koyarsanız ve her durumda returnuygun dizeyi varsa, breakifadeleri kaldırabilirsiniz .
Robert Harvey

Çözümünüz de en hızlısı.
Titou

8

Bu durumda switch ifadesi kodun amacına daha açık bir şekilde uyar: tek bir değere dayanarak yapılacak bir işlemi seçin.

Öte yandan if ifadeleri okumak çok daha zordur - neler olup bittiğinden emin olmak için hepsine bakmalısınız. Bana öyle (karakter sayısı bile az kod olabilir daha az olarak orada zihinsel ayrıştırmak biraz daha yüksek).


8

Jerry ile bir dizi karakter dizisinin bu özel durum için daha iyi olduğunu kabul ediyorum, ancak genel olarak bir switch / case ifadesini kullanmak başka bir zincirden daha iyidir. Okuması daha kolay ve bazen derleyici bu şekilde en iyi duruma getirme işini daha iyi yapabilir, ancak başka bir faydası daha var: hata ayıklaması çok daha kolay.

Bu anahtara bastığınız zaman, bir defada bir defada birkaç if ifadesi üzerine dikkatli bir şekilde geçmek yerine, muhtemelen çok hızlı bir şekilde basmak ve onu geçip bir şeyleri eksik olmak için sağ kolun üzerine çıkmak için yalnızca bir kez adım atmanız gerekir. baştan başlamak.


3

Bu tür durumlarda geçiş yapmayı tercih ediyorum, kodun noktasıyla daha iyi eşleşiyor, her farklı giriş değeri için farklı bir ifade yürütüyor. if..elseBir "hile" aynı etkiyi elde etmek için daha fazla gibi davranır.

switch ifadeleri de daha temiz, tüm bunlara gizlenmiş bir yazım hatası olması kolaydır ==

Ayrıca, C'deki büyük bloklar için anahtar daha hızlıdır.

else..ifaralıklar gibi bir şeye sahip olduğunuzda (1 ila 100 arasında, bunu yapın, 100 ila 200 arasında yapın) veya C'de, karakter dizileri gibi öğelerle geçiş yapmaya çalıştığınızda (diğer dillerde mümkün) daha uygun olabilir. Hangisi aynı.

C programladığımda birçok anahtar kullanmaya meyilliyim.


2

Verimli, özlü ve sonra yaptığınız şeyi değil, neden yaptığınızı belgeleyin .

Kod her zaman orijinal yazarı tarafından değil tekrar ziyaret edilebilir.

Bir uygulamayı diğerinden kasten seçeceğiniz zamanlar vardır, çünkü varolmayan kodu ileriye dönük olarak düşünüyorsunuz.


2

Genel olarak her iki yaklaşımı da sevmem. Uzun anahtar veya ifadeler sadece nesne yönelimli bir soyutlamaya yeniden yansıtılmaya başlarsa (ancak örneğinizde kısa değil, kısa olarak sınıflandırırım).

Şahsen bu tür kodları ayrı bir yardımcı yönteme sardım.

private string GetInsult()
{
    int which = (int)(Math.random() * 3);  //  Result is 0, 1, or 2.

    switch (which) {
        case 0: return "You look so much better than usual.";
        case 1: return "Your work is up to its usual standards.";
        case 2: return "You're quite competent for so little experience.";
        default: return "Oops -- something is wrong with this code.";
    }
}

public void Foo()
{
    string comment = GetInsult();
    Print(comment);
}

Anahtarı ayrı bir yönteme yerleştirmek, dönüş ifadelerini doğrudan switch ifadesinin içine (en azından c #) yerleştirerek, break ifadeleri ihtiyacını ortadan kaldırarak kodu okumayı çok kolaylaştırır.

Ve bu, eğer if / else if / else eğer yaklaşıyorsa çok daha güzel.


3
Kişisel olarak "başka bir yönteme koymak, çünkü çirkin görünüyor" gibi şeyleri çözmekten nefret ediyorum. Clutters yöntem listesi ve daha IMHO daha kötü görünüyor. Ben sadece kod kullanışlı başka bir yerde olabilir bir yerlerde veya B) yinelenmiş) A ise bu yapacağını
TheLQ

1
hangi yöntem listesi? ve neden metot listenizin kümelenmesi kodunuzun kümelenmesinden daha kötü durumda? Ben yaşı "bir kerede her şeyi görebilirsiniz böylece tek yöntemde tutmak her şey" geçmiş taşındı düşündük
sara

@TheLQ Genel olarak sizinle aynı fikirdeyim, ancak bu durumda "comment =" gerçekten Pete'in önerisi tarafından belirlenir.
Titou

0

Python'da switch ifadesi yoktur, çünkü / elif / else nice:

a = 5

if a==1:
    print "do this"
elif a == 2:
    print "do that"
elif a == 3:
    print "do the other"
elif 3 < a < 9:
    print "do more"
elif 9 <= a < 15:
    print "do nothing"
else:
    print "say sorry"

Basit değil mi?


Elifsadece birkaç harf eksik olan bir if ifadesidir. Bu kesinlikle ifbir switch ifadesinden çok bir açıklama gibidir. Python'un bir anahtarı OLMADIĞI gerçeği, onlardan nefret eden (benim gibi) yalnız olmadıklarını düşündürüyor.
Dan Rosenstark

Python biçimlendirme stackoverflow'ta çalışır ancak programmers.stackexchange.com adresinde çalışmaz :(
Christopher Mahan

metaBilinen bir konu olmadığı sürece onları uyarmalısın . Bana bir tanık verdiğin için teşekkürler.
Dan Rosenstark


1
@Yar, wikipedia yönetici günlerimi hatırlatıyor ... Ah Joy. (Henüz tamamen konu dışı mıyım?)
Christopher Mahan

0

C / C # stilini switchözellikle sinir bozucu yapan şeylerden biri , casedeğerin gerçek olması konusunda ısrar ediyor . VB / VB.NET ile ilgili güzel bir şey select/case, her bir vakanın herhangi bir boole ifadesi olmasına izin vermesidir. Bu uygun. Birbirini dışlayan bir dizi özel boole ifadesi olarak genellikle yararlıdır, eğer varsa / esnekse, yazmak ve okumak için daha verimli olmaktan ziyade, eğer daha esnekse.

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.