Lookup()和Dictionary(Of list())之间的区别


165

我正在努力寻找最有效的数据结构以及何时/何地使用哪种数据结构。

现在,可能是我只是对结构不够了解而已,但是它ILookup(of key, ...)与a Dictionary(of key, list(of ...))有何不同?

此外,ILookup在程序速度/内存/数据访问等方面,我想在哪里使用?在哪里使用效率更高?


Answers:


255

两个重大区别:

  • Lookup是一成不变的。是的:)(至少,我相信具体的Lookup类是不可变的,并且该ILookup接口不提供任何可变成员。当然,可能还有其他可变的实现。)
  • 当您查找在查找中不存在的键时,您会得到一个空序列,而不是KeyNotFoundException。(因此,没有TryGetValueAFAICR。)

它们的效率很可能相当-例如,查找可能会Dictionary<TKey, GroupingImplementation<TValue>>在幕后使用。根据您的要求在它们之间进行选择。我个人发现查找通常比a更合适Dictionary<TKey, List<TValue>>,主要是因为上面的前两点。

注意,作为一个实现细节,的具体实现IGrouping<,>,其用于值工具IList<TValue>,这意味着它是有效的与使用Count()ElementAt()等等。


如果不存在的键查找导致空序列而不是异常,则它非常不能用作通用集合imo。对于不可变集合(这是linq查询的副产品),这还可以。
nawfal 2014年

@nawfal-这正是查找的目的。来自msdn:“您可以通过在实现IEnumerable <T>的对象上调用ToLookup来创建Lookup <TKey,TElement>的实例。”
Niall Connaughton

50

有趣的是,没有人说出实际最大的差异(直接来自MSDN):

查找类似于字典。区别在于字典将键映射到单个值,而查阅将键映射到值的集合。


51
检查问题:这是关于Lookup <TKey,TValue>和Dictionary <TKey,List <TValue >>之间的区别,因此该区别已经很明显了。
Martao 2014年

5
@Martao有人在谷歌搜索以了解查找和字典之间的区别时发现了这个问题。这个答案真的很有用。
jakubiszon

34

a Dictionary<Key, List<Value>>Lookup<Key, Value>逻辑上都可以保存以相似方式组织的数据,并且两者的效率顺序相同。主要区别是a Lookup是不可变的:它没有Add()方法,也没有公共构造函数(并且正如Jon所述,您可以无例外地查询不存在的键并将该键作为分组的一部分)。

至于使用哪个,实际上取决于您要使用它们的方式。如果您要维护一个不断变化的键到多个值的映射,则a Dictionary<Key, List<Value>>可能更好,因为它是可变的。

但是,如果您有一系列数据,并且只想要按键组织的数据的只读视图,则查找非常容易构造,并且将为您提供只读快照。


11

an ILookup<K,V>和a 之间的主要区别Dictionary<K, List<V>>是字典是可变的;您可以添加或删除键,也可以从查找的列表中添加或删除项。an ILookup不可变的,一旦创建便无法修改。

这两种机制的基本实现将相同或相似,因此它们的搜索速度和内存占用量将大致相同。


1
@JohnBus​​tos在性能方面,没有。这纯粹是合乎逻辑的。您可以传递对结构的引用,而不必担心别人会从您的身下修改它。您可以假设这样的事实是可变的,如果它是可变的,那是不可变的。
Servy 2012年

谢谢,Servy,当您经常传递很多变量ByRef时,这是一个很好的方法-至少您确定不能修改此变量。谢谢!
约翰·布斯托斯

2
@JohnBus​​tos请记住,传递方法参数的默认方法是按值传递,您需要显式添加byref,而这种情况很少发生。这些数据结构是类,使它们成为引用类型,因此传递值就是引用的值,这就是为什么将其传递给另一个方法会对调用者造成可见变化的原因。
Servy 2012年

谢谢,Servy,就我一直在做的事情而言,它为我打开了一个全新的蠕虫罐头:),但我确实理解您的意思。谢谢!!
John Bustos 2012年

在幕后您是否知道Lookup是否使用哈希桶作为密钥?
狗仔队

10

尚未提及的另一个区别是Lookup()支持空键

查找类实现ILookup接口。查找与字典非常相似,只不过允许多个值映射到同一键,并且支持空键。


4

如果无法选择例外,请进行查找

如果您试图使结构像a一样有效,Dictionary但是您不确定输入中没有重复的键,那么这样做Lookup会更安全。

如另一个答案中所述,它还支持空键,并且在查询任意数据时始终返回有效结果,因此它对于未知输入更具弹性(不像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

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.