我有一个由一些复杂的表达式生成的ILookup。假设它是一个按姓氏查找的人。(在我们简单的世界模型中,姓氏按家庭是唯一的)
ILookup<string, Person> families;
现在我有两个查询,我对如何构建感兴趣。
- 首先,如何按姓氏进行筛选 *
var germanFamilies = families.Where(family => IsNameGerman(family.Key));
但在这里,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())));
这里我面临着两个问题:Grouping
类型并不存在(除了作为Lookup
的内部类),即使它存在,我们也会遇到上面讨论的问题。
那么,除了完全实现ILookup和IGrouping接口,或者让计算机做大量愚蠢的工作(对已经分组的内容进行重新分组)之外,有没有办法修改现有的ILookup以生成我错过的新的ILookup?
3条答案
按热度按时间lmvvr0a81#
(我假设您实际上希望根据查询按姓氏进行过滤。)
你不能修改我所知道的
ILookup<T>
的任何实现。当然,你也清楚地知道,implementToLookup
with an immutable lookup是可以修改的:)但是,您 * 可以 * 做的是改为使用
Dictionary<string, List<Person>>
:该方法也适用于第二个查询:
虽然这仍然比我们认为有必要做的工作多了一点,但也不算太坏。
编辑:评论中与Ani的讨论值得一阅读。基本上,我们已经在每个人身上进行了迭代--所以如果我们假设字典查找和插入的时间复杂度为O(1),那么实际上,使用现有的查找方法在时间复杂度方面并不比扁平化方法好多少:
在第一种情况下,我们可能会使用现有的分组,如下所示:
这可能会更有效(如果我们每个家庭都有很多人),但这意味着我们在“脱离上下文”地使用分组。我相信这实际上是好的,但出于某种原因,它在我嘴里留下了一点奇怪的味道。由于
ToLookup
具体化了查询,很难看到它实际上是如何出错的...qpgpyjmq2#
对于您的第一个查询,如何实现您自己的
FilteredLookup
,以便能够利用来自另一个ILookup
的查询?(感谢Jon Skeet的提示)
FilteredLookup
类为:和分组:
因此,基本上您的第一个查询将是:
这使您可以避免重新flattening-filtering-ToLookup,或者创建一个新的字典(从而再次散列键)。
对于第二个查询,想法是类似的,您应该只创建一个类似的类,而不是过滤整个
IGrouping
,而是过滤IGrouping
的元素。只是一个想法,也许它不可能比其他方法更快:)
f8rj6qna3#
查阅会建立具有索引键类型和实值类型一般索引子的索引。您可以使用concat进行新增和重复,并移除缓存清单中的索引键项目,然后重建查阅,以新增至查阅或从查阅中移除。然后查阅会像字典一样,依索引键撷取实值类型。
输出: