【C#/LINQ】Dictionaryの値の取得方法について時間を比較する

By | 2012年2月15日

Dictionaryから値を取得するには、インデクサを使ったり、LINQのFirst()メソッドやSingle()メソッドを使うことができる。
与えられるキーに対応する値が必ず存在するという前提で、これらの取得方法のかかる時間を計ってみることにした。

計測用に、以下のようなプログラムを書いてみた。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace DictionaryGetter
{
    class Program
    {
        private static int DATA_COUNT = 10000;

        static void Main(string[] args)
        {
            // アクセス用ディクショナリを作る
            var dict = Enumerable
                .Range(0, DATA_COUNT)
                .Select(x => new { Id = Guid.NewGuid(), Data = "data" })
                .ToDictionary(x => x.Id);

            // キーの値をシャッフルし、配列にしておく
            var keys = dict.Keys
                .OrderBy(key => Guid.NewGuid())
                .ToArray();


            var watch = new Stopwatch();

            // インデクサ
            watch.Reset();
            watch.Start();
            foreach (var key in keys)
            {
                var val = dict[key];
            }
            watch.Stop();
            Console.WriteLine("use indexer:\t" + watch.Elapsed.ToString());


            // First()メソッド
            watch.Reset();
            watch.Start();
            foreach (var key in keys)
            {
                var val = dict.First(x => x.Key == key);
            }
            watch.Stop();
            Console.WriteLine("use First():\t" + watch.Elapsed.ToString());


            // Single()メソッド
            watch.Reset();
            watch.Start();
            foreach (var key in keys)
            {
                var val = dict.Single(x => x.Key == key);
            }
            watch.Stop();
            Console.WriteLine("use Single():\t" + watch.Elapsed.ToString());
        }
    }
}

まず、16-19行目で検証用のDictionaryを作成している。
キーはGuid、値はGuid型のIdとString型のDataというフィールドを持つ匿名クラスである。
次に22行目でキーの値をシャッフルして配列にしておいた。
検証では、ここで並べられた順番でDictionaryにアクセスしていく。
その後はSystem.Diagtonics.StopWatchクラスを使って
インデクサ、First()メソッド、Single()メソッドを使ってDictionaryから値を取得する時間を計っている。

実行してみたところ、私の環境では以下のようになった。

use indexer: 00:00:00.0010259
use First(): 00:00:02.9547870
use Single(): 00:00:05.8560762
続行するには何かキーを押してください . . .

この結果を見る限りだと、Dictionaryから指定したKeyで値を取得したい、という普通の使い方ならば
普通にインデクサを使えば良さそうである。
そして、良く言われるとおりFirst()メソッドとSingle()メソッドではFirst()メソッドの方が速かった。
これは、First()メソッドは条件に合致した要素が見つかった時点で処理が終わるのに対し、
Single()メソッドはコレクション全体を探して、最後まで見つからなかった場合には例外を投げる必要があるからだろう。

コレクションの内容をシャッフルするのに参考にしたサイト:
http://dobon.net/vb/dotnet/programing/arrayshuffle.html


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です