僕の尊敬するJねっとさんが、switch case の最適化に関する話をしていたログをネット上で見かけました。
どのように最適化されるのかはわかりませんが、使用方法としての最適さは検証してみればわかるだろう・・・と言うことで早速試してみました。
用意したのは、以下のようなコードです。
(System, System.Collections, System.Diagnostics が using されています)
static void Main() {
string target = "j"; // ここを書き換える
Debug.WriteLine("------------------------------");
Debug.WriteLine("target:" + target);
Stopwatch stopWatch = new Stopwatch();
int count = 10000000;
//=====================================
stopWatch.Start();
for (int i = 0; i < count; ++i) {
string s = testIf(target);
}
stopWatch.Stop();
結果出力(stopWatch, "IF を使った場合");
//=====================================
stopWatch.Reset();
stopWatch.Start();
for (int i = 0; i < count; ++i) {
string s = testSwitch(target);
}
stopWatch.Stop();
結果出力(stopWatch, "Switch を使った場合");
//=====================================
Hashtable h = InitializeHashtable();
stopWatch.Reset();
stopWatch.Start();
for (int i = 0; i < count; ++i) {
string s = h[target].ToString();
}
stopWatch.Stop();
結果出力(stopWatch, "Hashtable を使った場合");
Debug.WriteLine("------------------------------");
}
static private Hashtable InitializeHashtable() {
Hashtable h = new Hashtable();
h.Add("a", "あ");
h.Add("b", "い");
h.Add("c", "う");
h.Add("d", "え");
h.Add("e", "お");
h.Add("f", "か");
h.Add("g", "き");
h.Add("h", "く");
h.Add("i", "け");
h.Add("j", "こ");
return h;
}
static string testSwitch(string i) {
switch (i) {
case "a": return "あ";
case "b": return "い";
case "c": return "う";
case "d": return "え";
case "e": return "お";
case "f": return "か";
case "g": return "き";
case "h": return "く";
case "i": return "け";
case "j": return "こ";
default: return "さ";
}
}
static string testIf(string i) {
if (i == "a") return "あ";
if (i == "b") return "い";
if (i == "c") return "う";
if (i == "d") return "え";
if (i == "e") return "お";
if (i == "f") return "か";
if (i == "g") return "き";
if (i == "h") return "く";
if (i == "i") return "け";
if (i == "j") return "こ";
return "さ";
}
static private void 結果出力(Stopwatch stopWatch, string message){
string s = message + ":" + stopWatch.ElapsedMilliseconds.ToString();
Debug.WriteLine(s.PadLeft(25));
}
結果は、次のようになりました。
------------------------------
target:a
IF を使った場合:316
Switch を使った場合:1281
Hashtable を使った場合:1787
------------------------------
target:j
IF を使った場合:2526
Switch を使った場合:1259
Hashtable を使った場合:1783
------------------------------
一番最初に見つかるであろう a をターゲットにした時「IF を使った場合」が素晴らしく早いことがわかります。
しかし、一番最後の j をターゲットにすると、一番遅くなってしまったのでした。選択肢が 10 しかないにも関わらず、です。
・・・ダメダメじゃんw
一方、Switch , Hashtable を使った場合は、共に安定した結果になりました。
つまり、Switch では、case を列挙した際の順序の差が出ないことがわかります。
ちなみに、実験では a をターゲットにした場合よりも j をターゲットにした場合の方が早くなっていますが、これは何度か実行すると数値が当然動きます。
つまりは誤差の範囲と考えてよいでしょう。
Hashtable も Switch Case と同様に登録順に関係ありません。
これは恐らく、Hash 値によって格納場所を対応付けしているから、探すという処理が不要になるためかと思われます。
Switch の方が幾分早いので、今回のような処理なら Swicth を使うのが最適な選択と言えそうです。
ただ、この件数が増えた場合は、Switch と Hashtable を使った結果が
変わるかも
しれません。(真意の程を誰か教えて下さい)