将递延的IEnumerable 分成两个序列,而无需重新评估?
|
我有一种方法需要处理输入的命令序列,然后根据结果的某些属性将结果分成不同的存储桶。例如:
class Pets
{
public IEnumerable<Cat> Cats { get; set; }
public IEnumerable<Dog> Dogs { get; set; }
}
Pets GetPets(IEnumerable<PetRequest> requests) { ... }
基础模型完全能够一次处理PetRequest
元素的整个序列,并且PetRequest
大多是通用信息,例如ID,因此尝试在输入处拆分请求没有任何意义。但是提供程序实际上并没有提供Cat
和Dog
实例,只是一个通用的数据结构:
class PetProvider
{
IEnumerable<PetData> GetPets(IEnumerable<PetRequest> requests)
{
return HandleAllRequests(requests);
}
}
我将响应类型命名为PetData
而不是Pet
,以明确表明它不是Cat
或Dog
的超类-换句话说,转换为Cat
或Dog
是映射过程。要记住的另一件事是12英镑很贵,例如数据库查询,所以我真的不想重复它,并且我宁愿避免使用ToArray()
之类的东西将结果缓存在内存中,因为可能有成千上万的结果(我有很多宠物) 。
到目前为止,我已经能够将这种笨拙的技巧归纳在一起:
Pets GetPets(IEnumerable<PetRequest> requests)
{
var data = petProvider.GetPets(requests);
var dataGroups =
from d in data
group d by d.Sound into g
select new { Sound = g.Key, PetData = g };
IEnumerable<Cat> cats = null;
IEnumerable<Dog> dogs = null;
foreach (var g in dataGroups)
if (g.Sound == \"Bark\")
dogs = g.PetData.Select(d => ConvertDog(d));
else if (g.Sound == \"Meow\")
cats = g.PetData.Select(d => ConvertCat(d));
return new Pets { Cats = cats, Dogs = dogs };
}
从某种意义上说,这不会使ѭ6的结果被枚举两次,但它在技术上是可行的,但是它有两个主要问题:
在代码上看起来像一个巨大的丘疹。它散发出我们在LINQ之前的框架2.0中一直必须使用的可怕的命令式风格。
最终这是一个完全没有意义的练习,因为GroupBy
方法只是将所有结果缓存在内存中,这意味着我真的比没有懒惰并先做了ToList()
更好。附加了一些谓词。
因此,重申一下这个问题:
是否可以将一个延迟的ѭ18实例拆分为两个IEnumerable<?>
实例,而无需执行任何急切的评估,将结果缓存在内存中或不必第二次重新评估原始的IEnumerable<T>
?
基本上,这将与“ 21”运算相反。 .NET框架中还没有一个事实,这强烈表明这甚至不可能实现,但是我认为无论如何也不会受到伤害。
附言请不要告诉我创建Pet
超类,而只返回IEnumerable<Pet>
。我使用Cat
和Dog
作为有趣的示例,但实际上结果类型更像Item
和Error
-它们都从相同的通用数据派生,但根本没有共同点。
没有找到相关结果
已邀请:
2 个回复
眠皇
那需要先处理所有的猫,然后处理所有的狗...所以如果第一个元素是
,那么原始序列会发生什么?它要么必须缓存它,要么跳过它-它不能返回它,因为我们仍然要30英镑。 您可以实现仅缓存所需数量的东西,但这很可能是一个序列的全部,因为典型用法是完全评估一个或另一个序列。 如果有可能,您真的只想在取宠物时处理宠物(无论是猫还是狗)。提供
和
并为每个项目执行正确的处理程序是否可行?
敦肌
但是我意识到这并不是您想要做的-但是您确实说过重新评估-而且只评估一次:)