2016-12-21 80 views
2

我必須編寫一個方法,返回按照這些對象的某些屬性分組的對象列表。我可以用linq的GroupBy成功完成它,但使用匿名類型,我不能發回給調用者。如果我嘗試按照here中的建議使用類來存儲IGrouping部分,那麼.GroupBy根本就不會組 - 這就好像密鑰關鍵字丟失了一樣,但我不能在強類型類中使用它們。如何在VB.Net中創建一個GroupBy,其結果可以從函數返回?

我搜索了很多 - 更因爲我懶得寫一個問題,因爲下面的stackoverflow問題準則 - 但我發現的大多數東西是C#相關,它沒有Key關鍵字的問題,還是關於單列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

的意思是相當於兩個GROUPBY功能呢? (函數中的函數和Main中的函數)。因爲目前他們不一樣,這可能是你得到不同結果的原因。它從一個函數返回的事實並不真正相關。 – ADyson

+1

編譯器不知道如何將'GroupedTrack'與另一個'GroupedTrack'進行比較,並通過引用來比較它們。 – Slai

+0

我是唯一一個在'返回lista.GroupBy(函數(f)新的帶有{.Data = f.Data,.Esdvn = f.Esdvn}的GroupedTrack')的錯誤。 –

回答

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

鑑於這是Key關鍵字的一個問題,我懷疑缺乏適當的比較方法是罪魁禍首,但我拒絕相信有很多hasle是必要的。 :p非常感謝大家! – Rekesoft

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已經實施了EqualsGetHashCode方法,因此您不必這樣做。 .GroupBy LINQ擴展使用Lookup來獲取組,因此您可以直接使用Lookup來避免.ToList

如果你分開,而比較關鍵的項目,你可以投匿名類型Object

Dim lookup As ILookup(Of Object, TrackHist) = 
     array.ToLookup(Function(t) CObj(New With {Key t.Data, Key t.Esdvn})) 
+0

有趣!不過,我會以正確的方式 - 這不是一個真正的問題,我只是認爲它必須是一個更簡單的方法。 – Rekesoft

相關問題