枚举ILookup结果的成本?始终使用Dictionary<TKey,List<TElement>>更好吗?

7

我有一个ILookup<TKey,TElement> lookup,我经常使用LINQ或foreach获取元素并遍历。我这样查找:IEnumerable<TElement> results = lookup[key];

因此,每次使用查找结果时都需要至少枚举一次results(如果不先使用.ToList(),则在多次迭代时需要枚举更多次)。

尽管这样做不够“干净”,但使用Dictionary<TKey,List<TElement>>是否更好(性能方面),以便从一个键中枚举所有结果仅在构建字典时进行?ToList()有多耗费性能?

2个回答

16
ToLookup与其他所有ToXXX LINQ方法一样,使用即时执行。生成的对象没有对原始源的引用。它有效地创建了一个Dictionary<TKey,List<TElement>>,可能不是确切的类型,但功能相当。
请注意,有一个区别,这可能对您有用,也可能没有 - 查找的索引器如果给定不存在的键,则返回一个空序列,而不是抛出异常。如果您想能够通过任何键进行索引并遍历相应的值,则可以使生活变得更加轻松。
还要注意,尽管它没有明确记录,但用于值序列的实现确实实现了ICollection<T>,因此调用LINQ的Count()方法是O(1) - 它不需要遍历所有元素。
有关更多详细信息,请参见我在ToLookup上的Edulinq文章

1
当我使用results时,ReSharper会警告我可能会多次枚举IEnumerable。如果我理解正确的话,我可以安全地忽略从ToLookup创建的ILookup的警告?(就像我可以忽略关于Count()的相同警告,因为它是O(1)吗?) - David S.
4
@David:是的,没错。在查找子序列上进行迭代是很便宜的。有时候ReSharper过于聪明反而不好用 ;) - Jon Skeet

4
假设实现是System.Linq.Lookup(是否有其他ILookup的实现?),在lookup[key]中呈现的元素存储在作为System.Linq.Lookup.Grouping字段的元素数组中。重复查找它们不会导致源代码重新迭代。当然,重建Lookup将更加昂贵,但一旦构建完成,源代码就不再被访问。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接