1. ホーム
  2. c#

[解決済み】辞書にキーが含まれていない場合に例外をキャッチするのではなく、辞書にキーが含まれているかどうかを確認する方が速いのはなぜですか?

2022-04-04 18:57:48

質問

コードを想像してください。

public class obj
{
    // elided
}

public static Dictionary<string, obj> dict = new Dictionary<string, obj>();

方法1

public static obj FromDict1(string name)
{
    if (dict.ContainsKey(name))
    {
        return dict[name];
    }
    return null;
}

方法2

public static obj FromDict2(string name)
{
    try
    {
        return dict[name];
    }
    catch (KeyNotFoundException)
    {
        return null;
    }
}

なぜなら、最初の関数は辞書に値が含まれているかどうかを2回チェックする必要があり、2番目の関数は辞書に1回アクセスするだけでいいからです。

1 000 000個の値(100 000個の既存値と900 000個の非既存値)に対してループをかける。

<ブロッククオート

最初の関数 306ミリ秒

2番目の関数:20483ミリ秒

なぜでしょうか?

EDIT: この質問の下のコメントでお気づきのように、実は、存在しないキーが0個の場合、2番目の関数の性能は1番目の関数より若干良いのです。しかし、少なくとも1つ以上のキーが存在する場合、2番目の関数の性能は急速に低下します。

解決方法は?

一方では 例外をスローすることは本質的にコストがかかる スタックを解放しなければならないからです。

一方、辞書の値をキーにしてアクセスするのは、O(1)の高速処理なので、安価です。

ちなみに、正しいやり方は TryGetValue

obj item;
if(!dict.TryGetValue(name, out item))
    return null;
return item;

これは辞書に2回アクセスするのではなく、1回だけアクセスします。

もし、本当に null が存在しない場合、上記のコードはさらに簡略化することができます。

obj item;
dict.TryGetValue(name, out item);
return item;

これは、次のように動作します。 TryGetValue セット item から null を持つキーがない場合は name が存在します。