2009-10-08 31 views
4

這段代碼會帶來哪些修改?在最後幾行,我應該用更多的的if-else結構,而不是 「如果 - 如果 - 如果」使用字符串選項優化if-else/switch-case

if (action.equals("opt1")) 
{ 
    //something 
} 
else 
{ 
    if (action.equals("opt2")) 
    { 
     //something 
    } 
    else 
    { 
     if ((action.equals("opt3")) || (action.equals("opt4"))) 
     { 
      //something 
     } 
     if (action.equals("opt5")) 
     { 
      //something 
     } 
     if (action.equals("opt6")) 
     { 
      //something 
     } 
    } 
} 

後來編輯:這就是Java。我不認爲switch-case結構可以和Strings一起使用。

後來編輯2:

的開關的工作原理與字節,短, 炭,和INT基本數據類型。它 也與枚舉類型 (中類和繼承討論) 和一些特殊類作品是「包裝」 某些基本類型:字符, 字節,短,和Integer(以簡單的數據對象討論 )。

+0

選項必須是字符串嗎?如果你可以讓它們成爲一個枚舉(或者當你獲得它時將字符串解析爲枚舉),那麼你可以使用一個開關。 – 2009-10-08 06:45:05

+1

請在提出這種問題時指定要「優化」的內容:例如可讀性,性能等。簡單地說:「你如何優化這些代碼?」沒有任何意義。我只提到這一點,因爲我看到一些迴應假定你的意思是性能,而另一些人則假設你的意思是可讀性 - 這實際上可能是互斥的優化。 – SingleShot 2009-10-08 07:25:18

+0

請將您的文章標題改爲:「優化帶字符串選項的if-else/switch-case」。目前的標題是沒有意義的。我會在此之後投票提出你的問題 – 2009-10-08 07:27:29

回答

10

即使你沒有使用switch語句,是的,如果避免無用的比較使用else:如果第一個如果被採用,你不希望所有其他ifs在這裏被評估,因爲他們會永遠是假的。同時你並不需要縮進各如果使得最後一塊如此縮進,你不能看到它不滾動,下面的代碼是完全可讀:

if (action.equals("opt1")) { 
} 
else if (action.equals("opt2")) { 
} 
else if (action.equals("opt3")) { 
} 
else { 
} 
+1

因爲Java顯然不能在字符串值上「切換」,所以我會採用這個人的方法。 (值得注意的是沒有壓抑) – Twisol 2009-10-08 06:43:52

+0

......雖然我仍然認爲你的大括號是錯誤的,但是這是一個完全沒有爭議的問題:) – mpen 2009-10-08 06:47:34

+0

比以前好,但對於最壞的情況仍然是O(n)。 – 2009-10-08 06:50:25

4

使用switch語句,假設您的語言支持切換字符串。

switch(action) 
{ 
    case "opt6": 
     // 
     break; 
    case "opt7": 
     // 
    ... 
    ... 
    ... 
} 
+0

這是Java,它不是。 – 2009-10-08 07:02:49

+1

在JDK 7中將引入字符串切換:http://blogs.sun.com/darcy/entry/project_coin_final_five – 2009-10-08 08:18:10

+0

有人知道這是否會編譯爲Java 7中的tableswitch字節碼指令?所以它會對if/else產生性能差異。 – 2009-10-08 08:24:24

2

您可以使用開關。

switch (action) 
{ 
case "opt3": 
case "opt4": 
doSomething; 
break; 
case "opt5": 
doSomething; 
break; 
default: 
doSomeWork; 
break; 
} 
1

這取決於你的語言,但它看起來類似C的,所以你可以嘗試的switch語句:

switch(action) 
{ 
case "opt1": 
    // something 
    break; 

case "opt2": 
    // something 
    break; 

case "opt3": 
case "opt4": 
    // something 
    break; 

case "opt5": 
    // something 
    break; 

case "opt6": 
    // something 
    break; 
} 

然而,有時switch語句沒有提供足夠的清晰度和靈活性(和正如Victor所指出的,在某些語言中不適用於字符串)。大多數編程語言將有說「否則,如果」,因此而不是寫

if (condition1) 
{ 
    ... 
} 
else 
{ 
    if (condition2) 
    { 
     ... 
    } 
    else 
    { 
     if (condition3) 
     { 
      ... 
     } 
     else 
     { 
      // This can get very indented very fast 
     } 
    } 
} 

...其中有凹痕的堆的方式,你可以寫這樣的事情:

if (condition1) 
{ 
    ... 
} 
else if (condition2) 
{ 
    ... 
} 
else if (condition3) 
{ 
    ... 
} 
else 
{ 
    ... 
} 

在C/C++,我相信C#,它是else if。在Python中,它是elif

+1

C不支持切換字符串。你將不得不使用strcmp或其他類似的else-ifs。 – 2009-10-08 06:39:28

+0

正確。請注意我的答案的後半部分;-) – Smashery 2009-10-08 06:42:34

0

建議使用開關的答案聲明是要走的路。 switch語句比現在使用的ifif...else語句更容易閱讀。

簡單的比較是快,//something代碼將不爲所有,但一個情況下執行,所以你可以跳過「優化」,去「維護」。

當然,這是假設action.equals()方法做一些小事,如==便宜。如果action.equals()很貴,您還有其他問題。

1

如果您指定語言,它可能會有所幫助......因爲它看起來像C++,所以可以使用開關。

switch (action) { 
    case "opt1": 
     // something 
     break; 
    case "opt2": 
     // something 
     break; 
    ... 
} 

而如果你想if語句,我想你可以提高可讀性和性能一點,如果你習慣用「否則,如果」無花括號,如:

if (action.equals("opt1")) { 
    //something 
} else if (action.equals("opt2")) { 
    //something 
} else if ((action.equals("opt3")) || (action.equals("opt4"))) { 
    //something 
} else if (action.equals("opt5")) { 
    //something 
} else if (action.equals("opt6")) { 
    //something 
} 

我認爲一些編譯器可以比else { if更好地優化else if。無論如何,我希望我能幫上忙!

+0

我認爲編譯器對'else'和'if'之間的大括號給出了一個該死的問題。 – Bombe 2009-10-08 07:00:51

1

我只想清理一系列的if/else語句:

if(action.equals("opt1")) 
{ 
    // something 
} 
else if (action.equals("opt2")) 
{ 
    // something 
} 
else if (action.equals("opt3")) 
{ 
    // something 
} 
etc... 
5

使用字典用字符串作爲鍵類型和代表*爲值類型。 - 從使用字符串檢索方法將採取O(1 +負載)。

在類的構造函數中填充字典。

  • Java不支持委託,因此作爲一項工作可能需要定義幾個內部類 - 每個案例一個,並傳遞內部類的實例而不是方法作爲值。
+1

如果有很多情況,Map 將會更好。對於if/else,這是O(1)與O(N)的映射。一切都取決於對地圖更大的不斷查找成本。 – 2009-10-08 07:07:40

+0

@Thomas:您的評論有誤導性。首先,並非所有的地圖都有O(1)查找成本;例如TreeMaps不,甚至HashMaps不使用一個愚蠢的負載因子。其次,對於具有默認(良好)加載因子的HashMap,查找代價取決於字符串的長度,是否先前對它進行了散列處理(字符串散列碼被緩存)以及散列碼是否爲字符串衝突。通過最佳案例假設,HashMap lookup **的攤銷成本可以比執行'if(key.equals(「value」)){'的成本低**。 – 2009-10-08 07:43:02

+0

@Stephen:你是對的。我記住了HashMap。是的,只有沒有散列衝突的查找纔會是0(1)。但是,我認爲一旦散列值被計算出來,查找速度就不依賴於字符串長度*,並且沒有衝突。只有在碰撞時,必須調用String.equals。這隻會在它嘗試實例平等之後。這隻會發生,如果你使用不同的字符串實例。但總的來說,你是對的,儘管它可以用於幾乎O(1)的表演。 – 2009-10-08 08:21:07

4

在Java中有很多方法可以做到這一點,但這裏是一個整潔的方法。

enum Option { 
    opt1, opt2, opt3, opt4, opt5, opt6 
} 

... 

switch (Option.valueOf(s)) { 
case opt1: 
    // do opt1 
    break; 
case opt2: 
    // do opt2 
    break; 
case opt3: case opt4: 
    // do opt3 or opt4 
    break; 
... 
} 

注意valueOf(String)將拋出IllegalArgumentException如果參數 不枚舉的成員之一的名稱。在底層,valueOf的實現使用靜態哈希映射將其String參數映射到枚舉值。

0

實際上這取決於分支分析。如果99%的決定是「opt1」,這個代碼已經很不錯了。如果你的決定中有99%是「opt6」,那麼這段代碼很糟糕。

如果在第一次比較中經常出現「opt6」並很少「opt1」出現「opt6」,並根據執行數據流中字符串的頻率進行下列比較。

如果你有很多選擇,並且都具有同等的頻率,你可以在選項進行排序,並將其分成二叉樹這樣的形式:

if (action < "opt20") 
{ 
    if(action < "opt10") 
    { 
    if(action == "opt4") {...} 
    else if(action == "opt2") {...} 
    else if(action == "opt1") {...} 
    else if(action == "opt8") {...} 
    } 
} 
else 
{ 
    if(action < "opt30) 
    { 

    } 
    else 
    { 
     if(action == "opt38") {...} 
     else if(action == "opt32") {...} 
    } 
} 

在此示例範圍拆分減少需要比較「opt38」和「opt4」爲3.這樣做後,您可以在每個分支中獲得log2(n)+1比較。這對於選項的相同頻率是最好的。

不要做二進制吐到最後,最後使用4-10「正常」否則,如果構造按選項的頻率排序。二叉樹中的最後兩個或三個級別沒有太多進展。

摘要

至少也有對這種比較兩個優化。

  1. 二元決策樹
  2. 訂貨由於二進制決策樹用於大的switch-case選項

頻率構建由編譯器。但編譯器不知道任何選項的頻率。因此,如果一個或兩個選項比其他選項頻繁得多,那麼根據頻率排序可以是使用開關盒的性能優勢。在這種情況下,這是一個解決辦法:

if (action == "opt5") // Processing a frequent (99%) option first 
{ 
} 
else // Processing less frequent options (>1%) second 
{ 
    switch(action) 
    { 
    case "opt1": ... 
    case "opt2": ... 
    } 
} 

警告

,直到你做了剖析不要優化你的代碼,它是真的有必要。最好使用開關盒,否則 - 如果直接向前,並且您的代碼保持清潔可讀。如果你已經優化你的代碼,在代碼中放置一些好評,這樣每個人都可以理解這種醜陋的代碼和平。一年後,你將不知道分析數據,一些評論將會非常有幫助。

+0

這樣的重寫應該由編譯器完成 – zproxy 2010-03-28 14:19:48

+0

@zproxy - 錯誤 - 編譯器不知道特定分支執行的頻率,程序員通常對此有個好主意。 – Derrick 2011-04-07 13:08:49

0

像這樣的過程切換通常更好地由多態處理 - 而不是由一個字符串表示的動作來代表具有可以專門化的「某種」方法的對象的動作。如果您發現您確實需要將字符串映射到該選項,請使用Map<String,Option>

如果你要堅持程序代碼,並在你的實際代碼的選項真的都是「OPTX」:

if (action.startsWith("opt") && action.length() == 4) { 
    switch (action.charAt(3)) { 
     case '1': something; break; 
     case '2': something; break; 
     case '3': something; break; 
     ... 
    } 
} 

這將是確定的東西像一個解析器(其中破串起來的部分的問題域),並且應該是快速的,但不是內聚的(對象action與行爲之間的連接基於其表示的部分,而不是對象的任何內在)。

0

如果您發現本機的java開關構建物太多限制給一目瞭然的lambdaj Switcher,讓他們與一些hamcrest的匹配匹配任何物體上以聲明方式進行切換。