我试图理解哪些数据结构是最有效的,以及何时/在哪里使用它们。
现在,可能只是因为我对这些结构不够了解,但是 ILookup (of key, ...)
与 Dictionary(of key, list(of ...))
有什么区别?
此外,在程序速度/内存/数据访问效率方面,我应该在哪里使用 ILookup
以及何时使用更加高效?
两个显著的不同点:
Lookup
是不可变的。太好了 :)(至少我认为具体的Lookup
类是不可变的,并且ILookup
接口没有提供任何变异成员。当然,可能会有其他可变实现。)KeyNotFoundException
。(因此,据我所知,没有TryGetValue
。)它们在效率上很可能是等效的 - 查找可能会在幕后使用Dictionary<TKey,GroupingImplementation<TValue>>
,例如。根据您的要求选择它们之间的区别。就个人而言,由于上面的前两个原因,我通常发现查找通常比Dictionary<TKey,List<TValue>>
更合适。
请注意,作为实现细节,用于值的IGrouping<,>
的具体实现实现IList<TValue>
,这意味着使用Count()
,ElementAt()
等非常高效。
有趣的是,没有人提到实际上最大的区别(直接从MSDN摘录):
查找(Lookup)类似于字典(Dictionary)。不同之处在于字典将键映射到单个值,而查找将键映射到值的集合。
grouping.ToDictionary(g => g.Key, g => g.ToList())
。 - OfirD一个 Dictionary<Key, List<Value>>
和一个 Lookup<Key, Value>
都可以逻辑上以类似的方式组织数据,并且两者的效率相同。主要区别在于 Lookup
是不可变的:它没有 Add()
方法和公共构造函数(正如Jon所提到的,您可以查询不存在的键而不会抛出异常,并将键作为分组的一部分)。
关于使用哪种方法,这取决于您希望如何使用它们。如果您正在维护一个不断修改的键对多个值的映射,那么 Dictionary<Key, List<Value>>
可能更好,因为它是可变的。
然而,如果您有一系列数据并且只想通过键来组织数据的只读视图,则很容易构建一个 lookup 并为您提供只读快照。
还有一个尚未提到的区别是,Lookup() 支持空键:
Lookup类实现了ILookup接口。Lookup与字典非常相似,但允许多个值映射到同一个键,并支持空键。
ILookup<K,V>
和 Dictionary<K, List<V>>
的主要区别在于字典是可变的,您可以添加或删除键,并且还可以添加或删除查找列表中的项。而 ILookup
是不可变的,创建后不能修改。ref
关键字,它会传递ValueType的引用或ReferenceType的引用的引用。 - Dave Black如果您想要一个像字典(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
需要为每个键维护一个项目列表,因此它比Dictionary
慢(对于大量项目约慢3倍)
查询速度: 创建:00:00:01.5760444
字典速度: 创建:00:00:00.4418833
list.ToLookup(x => x)
和 list.GroupBy(x => x).ToDictionary(group => group.Key)
是相等的。因为像你一开始所说的那样,Lookup可以枚举重复的元素。 - PM ExtraLookup
执行其未设计的操作时,即将1个键映射到1个值时,其性能会变差。 - Mr.Z