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


155

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

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

その説明は特に役に立ちません。Lookupは何に使用されますか?

回答:


215

それは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、これらの宣言のほとんどは通常のコードで使用します。)


59
私はこの答えをより良くするために、いくつかの変数を置き換えることができると思います。学習目的では、タイプが明確に表現されていると、理解しやすいと思います。ちょうど私の2セント:)
アレックスバラノスキー2009

3
それが両方の長所を持っているなら、なぜ辞書を気にするのですか?
Kyle Baran 2013年

15
@KyleBaran:キーごとに単一の値しかない、本物のキーと値のペアのコレクションには意味がないからです。
Jon Skeet 2013年

12
@KyleBaran Lookup<,>は、Add用途が限られている(たとえば、メソッドがない)不変のコレクションです。さらに、存在しないキーでルックアップを行うと、例外ではなく空のシーケンスを取得するという意味での汎用コレクションではありません。これは、linqなどの特別なコンテキストでのみ意味があります。これは、MSがクラスのパブリックコンストラクターを提供していないという事実とよく合います。
nawfal 2014年

解答の順番はjwg-> bobbymcr-> jonskeet
snr

58

これについて考える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
        }
    }
}

2
ルックアップ結果にゼロ要素はありますか?どうやってそれを手に入れますか?(私が知る限り、Lookupは公に不変であり、ToLookupが効果的にキーを発明することはないと思います。)
Jon Skeet

8
厳密に言うと、ルックアップは存在しないキーに対して空のコレクションを返すためです(これを示すコードサンプルを追加するために投稿を編集しました)。
bobbymcr 2009

解答の順番はjwg-> bobbymcr-> jonskeet
snr

非常にクリーンで役立つ回答です。選ばれたらいいのですが。

25

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

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

ここで、特定の電話番号が誰に属しているかを調べる方法が必要です。を作成しLookupKeyValuePairsからのすべてのを追加します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すでににあるキーは使用できないため、2行目に例外がスローされますDictionary

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


概念を理解するには答えが不可欠です。+1。回答の順序はjwg-> bobbymcr-> jonskeet
snr

15

私は以前にそれをうまく使用したことがありませんが、これが私の挑戦です:

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


5

電話帳の内容を保持するデータ構造を作成しているとしましょう。lastName、firstNameの順にキーを設定します。多くの人が同じ名前を持つことができるので、ここで辞書を使用するのは危険です。したがって、ディクショナリは常に、最大で1つの値にマッピングされます。

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

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


あなたの回答が私のフォローアップの質問「複数のインデックスを使用したToLookup()の方法」のきっかけになりました。複数のインデックスでルックアップを再現するにはどうすればよいですか?使用できる他のサンプルまたはリファレンスを使用して答えてもらえます Lookup["Smith"]["John"] か?
2013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.