どのデータ構造が最も効率的で、どのデータ構造をいつ/どこで使用するかを頭に入れようとしています。
さて、単に構造を十分に理解していないだけかもしれませんが、ILookup(of key, ...)
はDictionary(of key, list(of ...))
とどう違うのですか?
また、どこでILookup
を使用したいのでしょうか。また、プログラムの速度/メモリ/データへのアクセスなどの点でより効率的ですか?
2つの重要な違い:
Lookup
は不変です。 Yay :)(少なくとも、具体的なLookup
クラスは不変であり、ILookup
インターフェースは変化するメンバーを提供しないと信じています。(could他の可変実装、もちろん。)KeyNotFoundException
の代わりに空のシーケンスが返されます。 (したがって、TryGetValue
、AFAICRはありません。)効率的には同等である可能性が高い-たとえば、ルックアップは舞台裏でDictionary<TKey, GroupingImplementation<TValue>>
を使用する場合があります。要件に基づいて選択してください。個人的には、ほとんどの場合、上記の最初の2つの点が原因で、ルックアップはDictionary<TKey, List<TValue>>
よりも適しています。
実装の詳細として、値に使用されるIGrouping<,>
の具体的な実装はIList<TValue>
を実装することに注意してください。つまり、Count()
、ElementAt()
などで使用すると効率的です。
興味深いのは、実際の最大の違いについて誰も言及していないことです( MSDN から直接取得):
ルックアップは辞書に似ています。違いは、ディクショナリはキーを単一の値にマップするのに対して、ルックアップはキーを値のコレクションにマップすることです。
Dictionary<Key, List<Value>>
とLookup<Key, Value>
の両方が、同様の方法で編成されたデータを論理的に保持でき、どちらも同じ効率の順序です。主な違いはLookup
は不変です:Add()
メソッドもパブリックコンストラクターもありません(Jonが述べたように、例外なしで存在しないキーを照会し、そのキーをグルーピング)。
どちらを使用するかは、実際にどのように使用するかによって異なります。常に変更されている複数の値へのキーのマップを維持している場合、Dictionary<Key, List<Value>>
は可変であるため、おそらく優れています。
ただし、データのシーケンスがあり、キーで整理されたデータの読み取り専用ビューが必要な場合は、ルックアップを構築するのが非常に簡単で、読み取り専用のスナップショットが得られます。
ILookup<K,V>
とDictionary<K, List<V>>
の主な違いは、辞書が変更可能であることです。キーを追加または削除したり、検索されたリストからアイテムを追加または削除したりできます。 ILookup
は不変であり、作成後は変更できません。
両方のメカニズムの基礎となる実装は同じか類似しているため、検索速度とメモリフットプリントはほぼ同じになります。
まだ言及されていない別の違いは、Lookup() nullキーをサポート :
LookupクラスはILookupインターフェイスを実装します。ルックアップは、複数の値が同じキーにマップできることと、ヌルキーがサポートされていることを除いて、ディクショナリに非常に似ています。
Dictionary
と同じくらい効率的な構造を取得しようとしているが、入力に重複キーがないことを確実に知らない場合、Lookup
の方が安全です。
別の回答で述べたように、nullキーもサポートし、任意のデータを照会すると常に有効な結果を返すため、未知の入力に対してより回復力があるように見えます(例外が発生するのは辞書よりも少なくなります)。
そして、それをSystem.Linq.Enumerable.ToDictionary
関数と比較すると特に当てはまります。
// won't throw
new[] { 1, 1 }.ToLookup(x => x);
// System.ArgumentException: An item with the same key has already been added.
new[] { 1, 1 }.ToDictionary(x => x);
別の方法として、foreach
ループ内に独自の重複キー管理コードを記述する方法があります。
リストが不要で、膨大な数のアイテムを管理する場合は、Dictionary
(または独自のカスタム調整構造)の方が効率的です。
Stopwatch stopwatch = new Stopwatch();
var list = new List<string>();
for (int i = 0; i < 5000000; ++i)
{
list.Add(i.ToString());
}
stopwatch.Start();
var lookup = list.ToLookup(x => x);
stopwatch.Stop();
Console.WriteLine("Creation: " + stopwatch.Elapsed);
// ... Same but for ToDictionary
var lookup = list.ToDictionary(x => x);
// ...
Lookup
は各キーのアイテムのリストを保持する必要があるため、辞書よりも遅くなります(膨大な数のアイテムの場合は約3倍遅くなります)
ルックアップ速度:作成:00:00:01.5760444
辞書速度:作成:00:00:00.4418833