Lookup <TKey,TElement>有什么意义?


Answers:


215

这是an 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
我认为,要使此答案更好,您可以替换一些var。出于学习目的,当类型明确表达时,我认为更容易理解。只是我的2分钱:)
Alex Baranosky 09年

3
如果它兼有两全其美,那么为什么还要去字典呢?
凯尔·巴兰

15
@KyleBaran:因为对于真正的键/值对集合来说毫无意义,因为每个键只有一个值。
乔恩·斯基特

12
@KyleBaran Lookup<,>只是一个不可变的集合(Add例如,没有方法),它的使用受到限制。此外,从某种意义上说,它不是通用集合,如果您在不存在的键上进行查找,则会得到一个空序列而不是一个异常,这仅在特殊情况下才有意义,例如使用linq。这与MS没有为该类提供公共构造函数的事实相吻合。
nawfal 2014年

阅读答案的顺序是jwg-> bobbymcr-> jonskeet
snr

58

考虑的一种方法是: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
查找结果中可以有零个元素吗?你怎么得到的?(据我所知,查找是公开不变的,而且我认为ToLookup不会有效地发明密钥。)
Jon Skeet

8
从技术上讲,是的,因为查找返回了一个不存在的键的空集合(我编辑了我的文章以添加一个显示此内容的代码示例)。
bobbymcr

阅读答案的顺序是jwg-> bobbymcr-> jonskeet
snr

我希望这是一个非常干净且有用的答案。
分钟

25

的一种用法Lookup可能是反转Dictionary

假设您已将电话簿实现为,并Dictionary使用了一堆(唯一的)名称作为键,每个名称都与一个电话号码相关联。但是,两个名字不同的人可能共享相同的电话号码。对于而言Dictionary,这不是问题,它并不关心两个键对应于相同的值。

现在,您需要一种查找给定电话号码属于谁的方法。您可以构建一个LookupKeyValuePairs从中添加所有Dictionary,但向后添加,将值作为键,将键作为值。现在,您可以查询电话号码,并获取其电话号码所在的所有人的姓名列表。Dictionary使用相同的数据构建会丢弃数据(或失败,具体取决于您的操作方式),因为这样做

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

表示第二个条目将覆盖第一个条目-不再列出该文档。

尝试以略有不同的方式写入相同的数据:

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

会在第二行引发异常,因为您无法找到已存在Add的键Dictionary

[当然,您可能希望使用某些其他单一数据结构在两个方向上进行查找,依此类推。此示例意味着您必须LookupDictionary每次更改时都重新生成。但是对于某些数据,这可能是正确的解决方案。]


答案对于理解这个概念至关重要。+1。阅读答案的顺序为jwg-> bobbymcr-> jonskeet
snr

15

我以前没有成功使用过,但是这是我的努力:

Lookup<TKey, TElement>在没有唯一约束的情况下,A的行为几乎就像表上的(关系)数据库索引一样。在与其他地方相同的地方使用它。


5

我猜您可以这样争论:假设您正在创建一个数据结构来保存电话簿的内容。您要按lastName键,然后按firstName键。在这里使用字典会很危险,因为许多人可以使用相同的名字。因此,词典最多将始终映射到一个值。

查找将映射到可能的多个值。

Lookup [“ Smith”] [“ John”]的大小将达到10亿。


您的回答激发了我的后续问题“如何使用多个索引进行ToLookup()?” 。如何使用多个索引重现此类查询?您能否使用其他可能使用的示例或参考来回答问题 Lookup["Smith"]["John"]
完美的
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.