开发者

LINQ Group by with multiple properties in VB.Net

开发者 https://www.devze.com 2023-03-12 05:41 出处:网络
I spent a lot of time on this problem. I am able to do simple Group By LINQ queries (on one property) but for multiple fields I\'m a little stuck...

I spent a lot of time on this problem. I am able to do simple Group By LINQ queries (on one property) but for multiple fields I'm a little stuck... Here is a LINQPad sample of what I want to do :

dim lFinal={new with {.Year=2010, .Month=6, .Value1=0, .Value2=0}, 
            new with {.Year=2010, .Month=6, .Value1=2, .Value2=1},
            new with {.Year=2010, .Month=7, .Value1=3, .Value2=4},
            new with {.Year=2010, .M开发者_如何学Goonth=8, .Value1=0, .Value2=1},
            new with {.Year=2011, .Month=1, .Value1=2, .Value2=2},
            new with {.Year=2011, .Month=1, .Value1=0, .Value2=0}}

Dim lFinal2 = From el In lFinal
              Group el By Key = new with {el.Year,el.Month}
              Into Group
              Select New With {.Year = Key.Year, .Month=Key.Month, .Value1 = Group.Sum(Function(x) x.Value1), .Value2 = Group.Sum(Function(x) x.Value2)}

lFinal.Dump()
lFinal2.Dump()

The lFinal list has 6 items, I want the lFinal2 to have 4 items : 2010-6 and 2011-1 should group.

Thanks in advance.


Make the properties in the anonymous type immutable using the Key keyword and then they will be used for comparisons

    Dim lFinal2 = From el In lFinal               
    Group el By Key = new with {key el.Year, key el.Month} 
    Into Group
    Select New With {
          .Year = Key.Year, 
          .Month = Key.Month, 
          .Value1 = Group.Sum(Function(x) x.Value1),
          .Value2 = Group.Sum(Function(x) x.Value2)
    } 


Thanks ! But I noticed I needed to also write the GetHashCode function to make it works. I provide the VB.Net translation of the final class + LINQ GroupBy :

Class :

Public Class YearMonth
    Implements IEquatable(Of YearMonth)

    Public Property Year As Integer
    Public Property Month As Integer

    Public Function Equals1(other As YearMonth) As Boolean Implements System.IEquatable(Of YearMonth).Equals
        Return other.Year = Me.Year And other.Month = Me.Month
    End Function

    Public Overrides Function GetHashCode() As Integer
        Return Me.Year * 1000 + Me.Month * 100
    End Function
End Class

And the LINQ query :

Dim lFinal2 = From el In lFinal
              Group el By Key = New YearMonth With {.Year = el.Year, .Month = el.Month}
              Into Group
              Select New ItemsByDates With {.Year = Key.Year,
                                            .Month = Key.Month,
                                            .Value1 = Group.Sum(Function(x) x.Value1),
                                            .Value2 = Group.Sum(Function(x) x.Value2)}


Not 100% sure but group by probably uses the Equals() and/or GetHashCode implementation, so when you do the implicit creation:

= Group el By Key = new with {el.Year,el.Month}

the implicit object doesn't know to check both year and month (just because it has the properties doesn't mean it checks them when comparing to other objects).

So you'll probably need to do something more like this:

= Group el By Key = new CustomKey() { Year = el.Year, Month = el.Month };

public class CustomKey{
    int Year { get; set; }
    int Month { get; set; }

    public override bool Equals(obj A) {
        var key (CustomKey)A;
        return key.Year == this.Year && key.Month == this.Month;
    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消