我必须编写一个方法,返回按这些对象的某些属性分组的对象列表。我可以成功地使用linq的GroupBy,但使用匿名类型,我无法发回给调用者。如果我尝试使用类来存储here中建议的IGrouping部分,则.GroupBy根本不会分组 - 就像Key关键字丢失一样,但我不能强烈使用它们打字课。
我搜索了很多 - 更多是因为我懒得写一个问题,而不是因为遵循stackoverflow问题指南 - 但我发现的大部分内容都是C#相关的,没有问题关键字关键字,或关于单列GroupBy,或者它使用匿名类型,因为它不关心从函数或子函数返回参数,所以我做了一个小程序来说明情况。
Imports System.Globalization
Module Module1
Public Class TrackHist
Public Property Data As DateTime
Public Property Esdvn As String
Public Property Cmnts As String
Public Property IdCnt As String
End Class
Public Class GroupedTrack
Public Property Data As DateTime
Public Property Esdvn As String
End Class
Function Group(lista As List(Of TrackHist)) As List(Of IGrouping(Of GroupedTrack, List(Of TrackHist)))
Return lista.GroupBy(Function(f) New GroupedTrack With {.Data = f.Data, .Esdvn = f.Esdvn}).ToList
End Function
Sub Main()
Dim array As New List(Of TrackHist)
array.Add(New TrackHist() With {.Data = DateTime.ParseExact("10/01/2017", "dd/MM/yyyy", CultureInfo.InvariantCulture), .Cmnts = "Nothing", .Esdvn = "BIL", .IdCnt = "CN134234"})
array.Add(New TrackHist() With {.Data = DateTime.ParseExact("10/01/2017", "dd/MM/yyyy", CultureInfo.InvariantCulture), .Cmnts = "Nothing", .Esdvn = "BIL", .IdCnt = "CN284235"})
array.Add(New TrackHist() With {.Data = DateTime.ParseExact("10/01/2017", "dd/MM/yyyy", CultureInfo.InvariantCulture), .Cmnts = "Nothing", .Esdvn = "BIL", .IdCnt = "CN660003"})
array.Add(New TrackHist() With {.Data = DateTime.ParseExact("12/01/2017", "dd/MM/yyyy", CultureInfo.InvariantCulture), .Cmnts = "Nothing", .Esdvn = "LOA", .IdCnt = "CN134234"})
array.Add(New TrackHist() With {.Data = DateTime.ParseExact("12/01/2017", "dd/MM/yyyy", CultureInfo.InvariantCulture), .Cmnts = "Nothing", .Esdvn = "LOA", .IdCnt = "CN284235"})
array.Add(New TrackHist() With {.Data = DateTime.ParseExact("13/01/2017", "dd/MM/yyyy", CultureInfo.InvariantCulture), .Cmnts = "Nothing", .Esdvn = "LOA", .IdCnt = "CN660003"})
array.Add(New TrackHist() With {.Data = DateTime.ParseExact("15/01/2017", "dd/MM/yyyy", CultureInfo.InvariantCulture), .Cmnts = "Nothing", .Esdvn = "INSP", .IdCnt = "CN134234"})
array.Add(New TrackHist() With {.Data = DateTime.ParseExact("16/01/2017", "dd/MM/yyyy", CultureInfo.InvariantCulture), .Cmnts = "Nothing", .Esdvn = "DEP", .IdCnt = "CN284235"})
array.Add(New TrackHist() With {.Data = DateTime.ParseExact("16/01/2017", "dd/MM/yyyy", CultureInfo.InvariantCulture), .Cmnts = "Nothing", .Esdvn = "DEP", .IdCnt = "CN660003"})
Dim groupedAnonymous = array.GroupBy(Function(f) New With {Key f.Data, Key f.Esdvn}).ToList
Dim groupedTyped = Group(array)
Console.WriteLine("Grouped anonymous: {0} registers", groupedAnonymous.Count)
Console.WriteLine("Grouped typed: {0} registers", groupedTyped.Count)
End Sub
End Module
该程序产生以下输出:
分组匿名:5个寄存器 分组输入:9个寄存器
或者,换句话说,具有强类型对象的分组根本不是分组。那么,在VB.Net中创建GroupBy的正确方法是什么,其结果可以从函数返回?
答案 0 :(得分:1)
将Slai和Mark的评论转换成答案:
您的问题是您尚未定义将GroupedTrack
对象与另一个GroupedTrack
对象进行比较的方法;因此,当创建这些对象时,它们将通过引用进行比较,并且因为它们实际上是不同的对象,所以您将获得9个不同的值。
您需要做的是覆盖Equals()
和GetHashCode()
函数,以便编译器现在如何按值比较GroupedTrack
个对象。
这样的事情:
Public Class GroupedTrack
Public Property Data As DateTime
Public Property Esdvn As String
Public Overrides Function Equals(obj As Object) As Boolean
If obj Is Nothing Then Return False
If TypeOf obj IsNot GroupedTrack Then Return False
Return Me.Data = CType(obj, GroupedTrack).Data And Me.Esdvn = CType(obj, GroupedTrack).Esdvn
End Function
Public Overrides Function GetHashCode() As Integer
Return (Me.Data.ToString() & Me.Esdvn).GetHashCode()
End Function
End Class
(当你在那时,将你的功能定义更正为
Function Group(lista As List(Of TrackHist)) As List(Of IGrouping(Of GroupedTrack, TrackHist))
)
这样,两个分组都会产生一个包含5个元素的列表。
答案 1 :(得分:1)
如果“正确”的方式似乎太麻烦,懒惰的方式是使用类似的类型的键:
Function Group(items As IEnumerable(Of TrackHist)) As ILookup(Of String, TrackHist)
Return items.ToLookup(Function(t) t.Esdvn & t.Data)
End Function
我甚至不打算使用该函数,但关键是String
已经实现了Equals
和GetHashCode
方法,因此您不必这样做。
.GroupBy
LINQ扩展程序使用Lookup
来获取组,因此您可以直接使用.ToList
来避免Lookup
。
如果您想分别比较关键项,可以将匿名类型转换为Object
:
Dim lookup As ILookup(Of Object, TrackHist) =
array.ToLookup(Function(t) CObj(New With {Key t.Data, Key t.Esdvn}))