2011-04-06 67 views
0

我有2個來自2個不同系統的相似數據的表示,我需要將一個系統中的每個實體與另一個系統中的實體進行匹配。VB.NET LINQ - 匹配分層數據到平面數據

體系是分層次的,表示爲Dictionary(Of String, List(Of CategoryA))看起來像:

- "Organization 1" 
    - { Name = "Cat1", Id = 1} 
    - { Name = "Cat2", Id = 2} 
    - { Name = "Cat3", Id = 3} 

- "Organization 2" 
    - { Name = "Cat1", Id = 4} 
    - { Name = "Cat3", Id = 5} 
    - { Name = "Cat4", Id = 6} 

- "Organization 3" 
    - { Name = "Cat1", Id = 7} 
    - { Name = "Cat2", Id = 8} 
    - { Name = "Cat3", Id = 9} 
    - { Name = "Cat4", Id = 10} 

系統B是扁平的,表示爲List(Of CategoryB)看起來有點像:

- { Org = "Organization 1", Name = "Cat1", Id = 100 } 
- { Org = "Organization 1", Name = "Cat2", Id = 101 } 
- { Org = "Organization 1", Name = "Cat3", Id = 102 } 

- { Org = "Organization 2", Name = "Cat1", Id = 103 } 
- { Org = "Organization 2", Name = "Cat2", Id = 104 } 
- { Org = "Organization 2", Name = "Cat4", Id = 105 } 

- { Org = "Organization 4", Name = "Cat1", Id = 106 } 
- { Org = "Organization 4", Name = "Cat2", Id = 107 } 
- { Org = "Organization 4", Name = "Cat3", Id = 108 } 
- { Org = "Organization 4", Name = "Cat4", Id = 109 } 

,基本上我需要什麼do是將分層數據外部聯接到組織名稱(Dictionary.KeyCategoryB.Org)和類別名稱(CategoryA.NameCategoryB.Name)上的展開數據留下我一個Dictionary(Of String, IEnumerable(Of Tuple(Of CategoryA, CategoryB)))或東西看起來是這樣的:

- "Organization 1" 
    - { Name = "Cat1", Id = 1}, { Org = "Organization 1", Name = "Cat1", Id = 100 } 
    - { Name = "Cat2", Id = 2}, { Org = "Organization 1", Name = "Cat2", Id = 101 } 
    - { Name = "Cat3", Id = 3}, { Org = "Organization 1", Name = "Cat3", Id = 102 } 

- "Organization 2" 
    - { Name = "Cat1", Id = 4}, { Org = "Organization 2", Name = "Cat1", Id = 103 } 
    - { Name = "Cat3", Id = 5}, null 
    - { Name = "Cat4", Id = 6}, { Org = "Organization 2", Name = "Cat4", Id = 105 } 

- "Organization 3" 
    - { Name = "Cat1", Id = 7}, null 
    - { Name = "Cat2", Id = 8}, null 
    - { Name = "Cat3", Id = 9}, null 
    - { Name = "Cat4", Id = 10}, null 

我沒有訪問CategoryA目的是能夠給組織屬性適用於它,否則我會做它,使它更簡單對我自己。我只是無法弄清楚如何加入Dictionary鍵和它的值中的一個項的屬性,並最終得到任何有用的東西。我創建的最成功實施涉及For Each環路第一和LINQ查詢中:

Given: 
    catA = Dictionary(Of String, List(Of CategoryA)) 
    catB = List(Of CategoryB) 

Dim result As New Dictionary(Of String, List(Of Tuple(Of CategoryA, CategoryB))) 

For Each kvp As KeyValuePair(Of String, List(Of CategoryA)) In catA 
    Dim orgName As String = kvp.Key 

    If Not result.ContainsKey(orgName) Then 
     result.Add(orgName, New List(Of Tuple(Of CategoryA, CategoryB))) 
    End If 

    Dim orgCategories As IEnumerable(Of CategoryB) = 
     From cat In catB Where cat.Org = orgName 

    Dim tmpResult As IEnumerable(Of Tuple(Of CategoryA, CategoryB)) = 
     From cat_a In kvp.Value 
     Group Join cat_b In orgCategories 
      On cat_a.Name Equals cat_b.Name 
     Into matchedCats = Group 
     From cat In matchedCats.DefaultIfEmpty 
     Select matches = Tuple.Create(cat_a, cat) 

    result(orgName).AddRange(tmpResult) 
Next 

它的工作好了,但我想它是在同一個語句。

回答

0

那麼,這種有效的工作,但ID堅持你的循環!

Public Class CategoryA 
    Public Property Name As String 
    Public Property Id As Integer 
End Class 

Public Class CategoryB 
    Public Property Org As String 
    Public Property Name As String 
    Public Property Id As Integer 
End Class 

Private SystemA As New Dictionary(Of String, List(Of CategoryA)) 
Private SystemB As New List(Of CategoryB) 

Sub Main() 
    SystemA.Add("Org1", New List(Of CategoryA) From {New CategoryA() With {.Id = 1, .Name = "Cat1"}, 
                New CategoryA() With {.Id = 2, .Name = "Cat2"}, 
                New CategoryA() With {.Id = 3, .Name = "Cat3"}}) 
    SystemA.Add("Org2", New List(Of CategoryA) From {New CategoryA() With {.Id = 4, .Name = "Cat1"}, 
                New CategoryA() With {.Id = 5, .Name = "Cat2"}, 
                New CategoryA() With {.Id = 6, .Name = "Cat3"}}) 
    SystemA.Add("Org3", New List(Of CategoryA) From {New CategoryA() With {.Id = 7, .Name = "Cat1"}, 
                New CategoryA() With {.Id = 8, .Name = "Cat2"}, 
                New CategoryA() With {.Id = 9, .Name = "Cat3"}, 
                New CategoryA() With {.Id = 10, .Name = "Cat4"}}) 

    SystemB.Add(New CategoryB() With {.Org = "Org1", .Name = "Cat1", .Id = 100}) 
    SystemB.Add(New CategoryB() With {.Org = "Org1", .Name = "Cat2", .Id = 101}) 
    SystemB.Add(New CategoryB() With {.Org = "Org1", .Name = "Cat3", .Id = 102}) 
    SystemB.Add(New CategoryB() With {.Org = "Org2", .Name = "Cat1", .Id = 103}) 
    SystemB.Add(New CategoryB() With {.Org = "Org2", .Name = "Cat2", .Id = 104}) 
    SystemB.Add(New CategoryB() With {.Org = "Org2", .Name = "Cat4", .Id = 105}) 
    SystemB.Add(New CategoryB() With {.Org = "Org4", .Name = "Cat1", .Id = 106}) 
    SystemB.Add(New CategoryB() With {.Org = "Org4", .Name = "Cat2", .Id = 107}) 
    SystemB.Add(New CategoryB() With {.Org = "Org4", .Name = "Cat3", .Id = 108}) 
    SystemB.Add(New CategoryB() With {.Org = "Org4", .Name = "Cat4", .Id = 109}) 


    Dim AllOrgs = SystemA.Keys.Union(SystemB.Select(Function(b) b.Org).Distinct) 

    Dim BothCats2 = From org In AllOrgs 
        Let CatAList = If(Not SystemA.ContainsKey(org), New List(Of CategoryA), From cat In SystemA(org)) 
        Let CatBList = (From cat In SystemB Where cat.Org = org).ToList 
        Let AllCatNames = (From cat In CatAList Select cat.Name Distinct).Union(From cat In CatBList Select cat.Name Distinct) 
        Let BothCats = (From cat In AllCatNames 
            From A In CatAList.Where(Function(CatA) CatA.Name = cat).DefaultIfEmpty 
            From B In CatBList.Where(Function(CatB) CatB.Name = cat).DefaultIfEmpty) 
        Select org, BothCats 

End Sub