创建 ILookup

con*_*tor 5 linq ilookup

我有一个由一些复杂表达式生成的 ILookup。假设这是按姓氏查找人。(在我们简单化的世界模型中,姓氏在家庭中是唯一的)

ILookup<string, Person> families;
Run Code Online (Sandbox Code Playgroud)

现在我有两个疑问,我对如何构建感兴趣。

首先,我如何按姓氏过滤?

var germanFamilies = families.Where(family => IsNameGerman(family.Key));
Run Code Online (Sandbox Code Playgroud)

但这里germanFamilies有一个IEnumerable<IGrouping<string, Person>>; 如果我调用ToLookup()它,我最好打赌会得到一个IGrouping<string, IGrouping<string, Person>>. 如果我想聪明点,SelectMany先打电话,我最终会发现计算机做了很多不必要的工作。如何轻松地将这个枚举转换为查找?

其次,我只想查询成年人的信息。

var adults = families.Select(family =>
         new Grouping(family.Key, family.Select(person =>
               person.IsAdult())));
Run Code Online (Sandbox Code Playgroud)

在这里,我面临两个问题:Grouping类型不存在(除了作为 的内部内部类Lookup),即使存在,我们也会遇到上面讨论的问题。

那么,除了完全实现 ILookup 和 IGrouping 接口,或者让计算机做大量愚蠢的工作(重新分组已经分组的内容)之外,是否有办法改变现有的 ILookups 以生成我错过的新 ILookups?

Jon*_*eet 5

(根据您的查询,我假设您实际上想按姓氏进行过滤。)

您无法修改ILookup<T>我所知道的任何实现。正如您清楚地意识到的那样,当然可以使用不可变查找来实现ToLookup:)

但是,您可以做的是更改为使用Dictionary<string, List<Person>>

var germanFamilies = families.Where(family => IsNameGerman(family.Key))
                             .ToDictionary(family => family.Key,
                                           family.ToList());
Run Code Online (Sandbox Code Playgroud)

该方法也适用于您的第二个查询:

var adults = families.ToDictionary(family => family.Key,
                                   family.Where(person => persion.IsAdult)
                                         .ToList());
Run Code Online (Sandbox Code Playgroud)

虽然这仍然比我们认为必要的工作一些,但也不算太糟糕。

编辑:评论中与 Ani 的讨论值得一读。基本上,我们已经要迭代每个人了 - 所以如果我们假设 O(1) 字典查找和插入,那么使用现有查找的时间复杂度实际上并不比扁平化更好:

var adults = families.SelectMany(x => x)
                     .Where(person => person.IsAdult)
                     .ToLookup(x => x.LastName);
Run Code Online (Sandbox Code Playgroud)

在第一种情况下,我们可以使用现有的分组,如下所示:

// We'll have an IDictionary<string, IGrouping<string, Person>>
var germanFamilies = families.Where(family => IsNameGerman(family.Key))
                             .ToDictionary(family => family.Key);
Run Code Online (Sandbox Code Playgroud)

这可能会更有效(如果我们每个家庭都有很多人),但意味着我们正在“脱离上下文”使用分组。我相信这实际上没问题,但出于某种原因,它在我嘴里留下了一点奇怪的味道。当ToLookup具体化查询时,很难看出它实际上是如何出错的......