管理IEnumerable.GroupBy()的更有效方法

时间:2010-08-13 14:11:55

标签: c# .net-3.5 c#-3.0 lambda

这是我之前提出的问题:

Looking for a better way to sort my List<T>

基本上,我有类似的情况需要在大约40个不同的字段上执行.GroupBy()。

原始代码会使用一个巨大的switch语句,但我想知道是否有更好的方法。

我真正喜欢的是:

// not sure what the GroupBy selector function def should be...
Dictionary<PortfolioMapping, Func<Holding, ???>> groupByMappings;

我可以用来分组:

myPortfolioHoldings.GroupBy(groupByMaping[frmGroupBySelector.SelectedColumn]);

这样做的正确方法是什么?

2 个答案:

答案 0 :(得分:1)

您应该可以按object分组:

Dictionary<PortfolioMapping, Func<Holding, object>> groupByMappings;

只要您的映射函数返回:

,这将有效
  • 内置类型的实例(例如数字或字符串)
  • 实施IEquatable<T>
  • 的对象
  • 正确实施EqualsGetHashCode的对象

答案 1 :(得分:0)

好吧,我个人所做的是构建lambda表达式,然后将最终表达式应用到列表中。

我对Linq.Expression使用了一些扩展方法,它只包含如下内容:

<System.Runtime.CompilerServices.Extension()> _
Public Function Compose(Of T)(ByVal first As Expressions.Expression(Of T), ByVal second As Expressions.Expression(Of T), ByVal merge As Func(Of Expressions.Expression, Expressions.Expression, Expressions.Expression)) As Expressions.Expression(Of T)

    '' build parameter map (from parameters of second to parameters of first)
    Dim map = first.Parameters.[Select](Function(f, i) New With {f, .s = second.Parameters(i)}).ToDictionary(Function(p) p.s, Function(p) p.f)

    '' replace parameters in the second lambda expression with parameters from the first
    Dim secondBody = ParameterRebinder.ReplaceParameters(map, second.Body)

    '' applycomposition of lambda expression bodies to parameters from the first expression 
        Return Expressions.Expression.Lambda(Of T)(merge(first.Body, secondBody), first.Parameters)
    End Function

<System.Runtime.CompilerServices.Extension()> _
Public Function [And](Of T)(ByVal first As Expressions.Expression(Of Func(Of T, Boolean)), ByVal second As Expressions.Expression(Of Func(Of T, Boolean))) As Expressions.Expression(Of Func(Of T, Boolean))
    Return first.Compose(second, AddressOf Expressions.Expression.And)
End Function

然后你可以建立这样的查询:

Dim MyQuery as Linq.Expressions.Expression(Of System.Func(Of MyListDataType, Boolean))
Dim MyGroupingExpression as Linq.Expressions.Expression(Of System.Func(Of MyListDataType, Boolean))

Dim MyQuery = Function(x) x.SomeValue = SomeExpectedValue
Select case SomeOtherVariable
    Case Option1
        Dim MyGroupingExpression = <blah>
    Case Option2
        Dim MyGroupingExpression = <blah>
End Select

Dim Results = MyList.Where(MyQuery.And(GroupingExpression))

这就是你要追求的吗?