web-dev-qa-db-ja.com

Lookup <TKey、TElement>のポイントは何ですか?

MSDNはLookupを次のように説明しています。

Lookup<TKey, TElement>Dictionary<TKey, TValue> に似ています。違いは、Dictionary <TKey、TValue>はキーを単一の値にマッピングするのに対して、Lookup <TKey、 TElement>は、キーを値のコレクションにマップします。

私はその説明が特に役立つとは思わない。 Lookupは何に使用されますか?

142
dan-gph

IGroupingと辞書のクロスです。キーによってアイテムをグループ化できますが、そのキーを介して効率的な方法でそれらにアクセスできます(すべてを繰り返し処理するのではなく、GroupByでできます)。

たとえば、.NETタイプのロードを取得し、ネームスペースによるルックアップを構築することができます...その後、特定のネームスペース内のすべてのタイプを非常に簡単に取得できます。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;

public class Test
{
    static void Main()
    {
        // Just types covering some different assemblies
        Type[] sampleTypes = new[] { typeof(List<>), typeof(string), 
                                     typeof(Enumerable), typeof(XmlReader) };

        // All the types in those assemblies
        IEnumerable<Type> allTypes = sampleTypes.Select(t => t.Assembly)
                                               .SelectMany(a => a.GetTypes());

        // Grouped by namespace, but indexable
        ILookup<string, Type> lookup = allTypes.ToLookup(t => t.Namespace);

        foreach (Type type in lookup["System"])
        {
            Console.WriteLine("{0}: {1}", 
                              type.FullName, type.Assembly.GetName().Name);
        }
    }
}

(通常のコードでは、これらの宣言のほとんどにvarを通常使用します。)

204
Jon Skeet

それについて考える1つの方法はこれです:Lookup<TKey, TElement>Dictionary<TKey, Collection<TElement>>に似ています。基本的に、ゼロ以上の要素のリストは、同じキーを介して返されます。

namespace LookupSample
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    class Program
    {
        static void Main(string[] args)
        {
            List<string> names = new List<string>();
            names.Add("Smith");
            names.Add("Stevenson");
            names.Add("Jones");

            ILookup<char, string> namesByInitial = names.ToLookup((n) => n[0]);

            // count the names
            Console.WriteLine("J's: {0}", namesByInitial['J'].Count()); // 1
            Console.WriteLine("S's: {0}", namesByInitial['S'].Count()); // 2
            Console.WriteLine("Z's: {0}", namesByInitial['Z'].Count()); // 0, does not throw
        }
    }
}
56
bobbymcr

Lookupの用途の1つは、Dictionaryを逆にすることです。

電話帳がDictionaryとして実装されており、それぞれの名前が電話番号に関連付けられた一連の(一意の)名前をキーとしているとします。ただし、名前の異なる2人が同じ電話番号を共有する場合があります。これはDictionaryの問題ではありません。2つのキーが同じ値に対応していることを気にしません。

ここで、特定の電話番号が誰に属しているかを検索する方法が必要です。 Lookupを作成し、KeyValuePairsからDictionaryをすべて追加しますが、値をキーとして、キーを値として逆方向に追加します。これで、電話番号を照会し、その電話番号を持つすべての人々の名前のリストを取得できます。同じデータを使用してDictionaryを構築すると、データがドロップされます(または、その方法によっては失敗します)。

dictionary["555-6593"] = "Dr. Emmett Brown";
dictionary["555-6593"] = "Marty McFly";

は、2番目のエントリが最初のエントリを上書きすることを意味します-ドキュメントはリストされなくなります。

同じデータをわずかに異なる方法で書き込もうとしています:

dictionary.Add("555-6593", "Dr. Emmett Brown");
dictionary.Add("555-6593", "Marty McFly");

既にAddにあるキーをDictionaryできないため、2行目に例外がスローされます。

[もちろん、他の単一のデータ構造を使用して両方向などのルックアップを行うこともできます。この例は、後者が変更されるたびにLookupからDictionaryを再生成する必要があることを意味します。しかし、一部のデータでは、適切なソリューションになる可能性があります。]

22
jwg

私はそれを前にうまく使ったことがありませんが、ここに私の行くことがあります:

Lookup<TKey, TElement>は、一意制約のないテーブルの(リレーショナル)データベースインデックスとほとんど同じように動作します。他の場所と同じ場所で使用してください。

14
Daren Thomas

このように議論できると思います。電話帳の内容を保持するデータ構造を作成していると想像してください。 lastNameでキーを入力し、次にfirstNameでキーを入力します。多くの人が同じ名前を持つことができるため、ここで辞書を使用すると危険です。したがって、ディクショナリは常に最大で1つの値にマップされます。

Lookupは、潜在的にいくつかの値にマップされます。

Lookup ["Smith"] ["John"]は、サイズが10億のコレクションになります。

5
David Andres