为LINQ伪造IGrouping

时间:2009-07-08 20:45:54

标签: c# linq optimization

想象一下,您有一个大型数据集,可能会或可能不会被数据集元素的特定条件过滤,这些条件可能需要进行密集计算。在未过滤的情况下,元素按该条件的值分组 - 条件计算一次。

但是,在进行过滤的情况下,虽然后续代码仍然希望看到IEnumerable<IGrouping<TKey, TElement>>集合,但执行导致的GroupBy操作没有意义每个元素第二次重新评估条件。相反,我希望能够通过适当地包装过滤结果来创建IEnumerable<IGrouping<TKey, TElement>>,从而避免对条件进行另一次评估。

除了实现我自己的提供IGrouping接口的类之外,还有其他方法可以实现此优化吗?是否存在支持这种情况的LINQ方法,这会给我IEnumerable<IGrouping<TKey, TElement>>结果?还有其他方法我没有考虑过吗?

3 个答案:

答案 0 :(得分:3)

  

条件计算一次

我希望那些钥匙还在某个地方......

如果你的数据是这样的结构:

public class CustomGroup<T, U>
{
  T Key {get;set;}
  IEnumerable<U> GroupMembers {get;set} 
}

您可以使用以下查询投影此类项目:

var result = customGroups
  .SelectMany(cg => cg.GroupMembers, (cg, z) => new {Key = cg.Key, Value = z})
  .GroupBy(x => x.Key, x => x.Value)

答案 1 :(得分:2)

受到David B's answer的启发,我提出了一个简单的解决方案。这么简单,我不知道我是怎么错过它的。

为了执行过滤,我显然需要知道我过滤的条件的值。因此,给定条件c,我可以将筛选后的列表投影为:

filteredList.GroupBy(x => c)

这可以避免重新计算元素的属性(由x表示)。

我意识到的另一个解决方案是在执行过滤之前反转查询的顺序并执行分组。这也意味着条件只被评估一次,尽管它会不必要地分配我不会随后使用的分组。

答案 2 :(得分:0)

如何将结果放入LookUp并在剩下的时间内使用它?

var lookup = data.ToLookUp(i => Foo(i));