Lookup()とDictionary(Of list())の違い


165

どのデータ構造が最も効率的で、いつ/どこでどのデータ構造を使用するかについて頭を抱えようとしています。

今、私は単に構造を十分に理解していないだけかもしれませんが、どうILookup(of key, ...)違うのDictionary(of key, list(of ...))ですか?

また、どこで使用しILookup、どこでプログラム速度/メモリ/データアクセスなどの点でより効率的ですか?


回答:


255

2つの大きな違い:

  • Lookup不変です。Yay :)(少なくとも、具象Lookupクラスは不変であり、ILookupインターフェースは変更メンバーを提供しないと思います。もちろん、他の変更可能な実装もあるでしょう。)
  • ルックアップに存在しないキーをルックアップすると、の代わりに空のシーケンスが返されKeyNotFoundExceptionます。(したがってTryGetValue、AFAICRはありません。)

それらは効率的に同等である可能性があります- Dictionary<TKey, GroupingImplementation<TValue>>たとえば、ルックアップは舞台裏でよく使用するかもしれません。要件に基づいてそれらから選択してください。個人的には、ルックアップは通常、aよりも適していることがわかります。これはDictionary<TKey, List<TValue>>、主に上記の最初の2つの点が原因です。

実装の詳細として、その具体的な実装がIGrouping<,>値implementsに使用されることに注意してください。これは、などでIList<TValue>使用すると効率的であることを意味します。Count()ElementAt()


存在しないキールックアップの結果、例外ではなく空のシーケンスが発生する場合は、汎用のコレクションimoとして使用できません。linqクエリの副産物である不変コレクションの場合は、まあまあです。
nawfal 2014年

@nawfal-それがまさにLookupsの目的です。msdnから:「IEnumerable <T>を実装するオブジェクトでToLookupを呼び出すことにより、Lookup <TKey、TElement>のインスタンスを作成できます。」
Niall Connaughton 2015

50

興味深いのは、実際の最大の違いについて誰も述べていないことです(MSDNから直接取得)。

ルックアップは辞書に似ています。違いは、Dictionaryはキーを単一の値にマップするのに対し、Lookupはキーを値のコレクションにマップするということです。


51
質問を確認してください。それは、Lookup <TKey、TValue>とDictionary <TKey、List <TValue >>の違いに関するものであり、その違いはすでに明白です。
Martao 2014年

5
@Martao一部の人々は、検索と辞書の違いを理解するためにグーグルするときにこの質問を見つけます。この答えは本当に役に立ちます。
ジャクビゾン

34

両方Dictionary<Key, List<Value>>Lookup<Key, Value>論理的に同様の方法で編成されたデータを保持し、両方の効率と同程度であることができます。主な違いはLookupは不変です:Add()メソッドもパブリックコンストラクターもありません(Jonが述べたように、例外なしで存在しないキーをクエリして、グループ化の一部としてキーを持つことができます)。

どちらを使用するかは、実際の使用方法によって異なります。常に変更されている複数の値へのキーのマップを維持している場合Dictionary<Key, List<Value>>は、変更可能であるため、おそらくaの方が適しています。

ただし、データのシーケンスがあり、キーで編成されたデータの読み取り専用ビューのみが必要な場合、ルックアップは非常に簡単に作成でき、読み取り専用のスナップショットが得られます。


11

an ILookup<K,V>とa の主な違いDictionary<K, List<V>>は、辞書が変更可能であることです。キーを追加または削除したり、検索されたリストにアイテムを追加または削除したりできます。AnがILookupある不変と作成した後に変更することはできません。

両方のメカニズムの基礎となる実装は同じまたは類似しているため、検索速度とメモリフットプリントはほぼ同じになります。


1
@JohnBus​​tosパフォーマンスの面では、違います。それは純粋に論理的です。他の誰かがあなたの下から構造を変更することを心配しないで、構造への参照を渡すことができます。それが不変であるということは、それが変更可能である場合には不可能であったという事実を前提とすることができます。
12

おかげで、Servy、ByRefを非常に多くの変数で渡す場合に非常に良い点です。少なくとも、これは変更できないはずです。ありがとう!
John Bustos、

2
@JohnBus​​tosメソッドパラメータを渡すデフォルトの方法は値によるものであり、byrefを明示的に追加する必要があることを覚えておいてください。これらのデータ構造はクラスであり、それらは参照型になります。そのため、値を渡すと参照の値になります。そのため、別のメソッドに渡すと、呼び出し元に目に見える変化が生じる可能性があります。
12

おかげで、私はこれまでにしてきたことに関して、まったく新しいワームの缶を開いてくれます:)が、私はあなたの言っていることを理解しています。ありがとう!!
John Bustos、

LookupがLookupがキーにハッシュバケットを使用するかどうか知っていますか?
パパラッツォ

10

まだ言及されていないもう1つの違いは、Lookup()がnullキーをサポートすることです。

LookupクラスはILookupインターフェイスを実装します。ルックアップは、複数の値を同じキーにマップできること、およびnullキーがサポートされていることを除いて、ディクショナリと非常に似ています。


4

例外が選択できない場合は、ルックアップに進みます

と同じくらい効率的な構造を取得しようとしている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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.