Lookup<TKey, TElement>
类似于Dictionary<TKey, TValue>
,不同之处在于Dictionary<TKey, TValue>将键映射到单个值,而Lookup<TKey, TElement>将键映射到值的集合。
我觉得这个解释并不是特别有用。那么Lookup是用来做什么的?
Lookup<TKey, TElement>
类似于Dictionary<TKey, TValue>
,不同之处在于Dictionary<TKey, TValue>将键映射到单个值,而Lookup<TKey, TElement>将键映射到值的集合。
我觉得这个解释并不是特别有用。那么Lookup是用来做什么的?
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
来声明大多数变量。
从一个角度来看,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
}
}
}
Dictionary
。假设您的电话簿已实现为一个Dictionary
,其中许多(唯一)名称作为键,每个名称关联一个电话号码。但具有不同名称的两个人可能共享相同的电话号码。对于不关心两个键对应于相同值的Dictionary
来说,这不是问题。
现在你想要一种查找给定电话号码所属者的方法。您可以构建一个Lookup
,将所有KeyValuePairs
从您的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");
第二行会抛出异常,因为你不能在Dictionary
中添加已经存在的键。
[当然,你可能想使用其他单个数据结构来进行双向查找等操作。这个例子意味着每次更改后者,都必须从前者重新生成Lookup
。但对于某些数据来说,这可能是正确的解决方案。]
Lookup<_, Person>
的等价物不是Dictionary<_, Person>
,而是Dictionary<_, Bag<Person>>
。从一个ILookup<PhoneId, Person>
中,myLookup["555-6593"]
的结果不是一个人“Dr. Emmett Brown”,而是一组人{ "Dr. Emmett Brown" }
!因此,在访问您的等效字典时,您不能执行dictionary.Add("555-6593", "Dr. Emmett Brown");
,因为它需要一个列表;您必须获取或创建该列表,然后将其添加到列表中。 - ANeves我之前没有成功使用过,但以下是我的尝试:
Lookup<TKey, TElement>
的行为与没有唯一约束条件的表上的(关系)数据库索引基本相同。在与其他相同的地方使用它。
我想你可以这样解释:假设你正在创建一个数据结构来保存电话簿的内容。你想按姓氏和名字排序。在这里使用字典会很危险,因为许多人可能有相同的姓名。因此,字典始终最多只能映射到单个值。
查找将可能映射到多个值。
Lookup["Smith"]["John"] 将是一个大小为十亿的集合。
Lookup["Smith"]["John"]
? - Fulproof补充说明:
ToLookup
是立即执行,并会将结果缓存到内存中。但是,GroupBy
是延迟执行的,不会缓存分组结果,每次调用时都会重新进行分组。
如果您需要重复访问“已分组的固定数据”,则应选择ToLookUp
以获取LookUp实例。特别是当数据量大或多次访问数据时,使用GroupBy会导致严重的性能问题-ToLookUp
以使用更多内存为代价,缓存的分组结果将为您的代码提供更好的性能。
顺便说一下:LookUp
有时可以用作“EasyDictionary”,因为它不会在不存在的键上抛出异常。
Lookup<,>
是一个简单的不可变集合(例如没有Add
方法),其用途有限。此外,它不是一般意义上的集合,如果对不存在的键进行查找,则会返回空序列而不是异常。这在特定情境下才有意义,例如与linq一起使用。这也解释了为什么Microsoft没有提供公共构造函数给这个类。 - nawfal