どのデータ構造が最も効率的で、いつ/どこでどのデータ構造を使用するかについて頭を悩ませようとしています。
さて、構造がよくわからないだけかもしれませんが、どうILookup(of key, ...)
違うのDictionary(of key, list(of ...))
?
また、どこで使用したいのですかILookup
、プログラム速度/メモリ/データアクセスなどの点でどこでより効率的ですか?
2つの重要な違い:
Lookup
不変です。Yay :)(少なくとも、具象Lookup
クラスは不変であり、ILookup
インターフェースは変更メンバーを提供しないと思います。もちろん、他の変更可能な実装がある可能性があります。)KeyNotFoundException
。(したがってTryGetValue
、AFAICRはありません。)効率は同等である可能性がありますDictionary<TKey, GroupingImplementation<TValue>>
。たとえば、ルックアップでは舞台裏を使用する場合があります。要件に基づいてそれらから選択してください。個人的には、ルックアップは通常、上記の最初の2つのポイントが原因で、よりも適していることがわかりましたDictionary<TKey, List<TValue>>
。
実装の詳細として、値に具体的な実装IGrouping<,>
が使用されていることに注意してください。これは、などIList<TValue>
で使用するのが効率的であることを意味します。Count()
ElementAt()
誰も実際の最大の違いを述べていないのは興味深いことです(MSDNから直接取得):
ルックアップは辞書に似ています。違いは、ディクショナリがキーを単一の値にマップするのに対し、ルックアップはキーを値のコレクションにマップすることです。
aDictionary<Key, List<Value>>
とLookup<Key, Value>
論理的にはどちらも同様の方法で編成されたデータを保持でき、どちらも同じ程度の効率です。主な違いは、Lookup
が不変であるということです。Add()
メソッドもパブリックコンストラクターもありません(Jonが述べたように、例外なく存在しないキーをクエリし、グループ化の一部としてキーを使用できます)。
どちらを使用するかは、実際にどのように使用するかによって異なります。絶えず変更されている複数の値へのキーのマップを維持している場合は、Dictionary<Key, List<Value>>
変更可能であるため、おそらくaの方が適しています。
ただし、一連のデータがあり、キーごとに整理されたデータの読み取り専用ビューが必要な場合は、ルックアップの作成が非常に簡単で、読み取り専用のスナップショットが得られます。
まだ言及されていないもう1つの違いは、Lookup()がnullキーをサポートしていることです。
LookupクラスはILookupインターフェースを実装します。ルックアップは辞書と非常によく似ていますが、複数の値を同じキーにマップでき、nullキーがサポートされている点が異なります。
ILookup<K,V>
anとaの主な違いはDictionary<K, List<V>>
、辞書が変更可能であることです。キーを追加または削除したり、検索されたリストからアイテムを追加または削除したりできます。AnILookup
は不変であり、一度作成すると変更できません。
両方のメカニズムの基本的な実装は同じか類似しているため、検索速度とメモリフットプリントはほぼ同じになります。
と同じくらい効率的な構造を取得しようとしているDictionary
が、入力に重複するキーがないことを確認できない場合は、Lookup
より安全です。
別の回答で述べたように、nullキーもサポートし、任意のデータでクエリを実行すると常に有効な結果を返すため、不明な入力に対してより回復力があるように見えます(Dictionaryよりも例外が発生する傾向がありません)。
そして、それを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