2010-08-18 2 views
1

Framework 2.0에서 VB.NET을 사용하고 있습니다. 두 가지 속성으로 일반 목록 <을 빨리 그룹화하고자합니다. 이 예제에서 CustomerId, ProductId 및 ProductCount의 속성을 가진 Order 형식의 목록이 있다고 가정 해 보겠습니다. VB.NET에서 CustomerId 및 ProductId별로 그룹화 된 ProductCounts의 평균을 얻으려면 어떻게해야합니까?GroupBy 2 개의 값을 VB.NET의 일반 목록에 넣으시겠습니까?

불행히도 DB 수준에서이 작업을 수행 할 수 없습니다 (쉬운 방법). 또한 Framewwork 2.0에서 LINQ 나 Lambada를 Im으로 사용할 수 없습니다. 그래서 VB.net의 응용 프로그램 수준에서이 작업을 수행해야합니다. 목록은 CustomerId와 ProductId에 의해 정렬되어 반환됩니다. 그래서 나는 약간의 루프를 가지고 평균 값을 생성 할 수있을 것입니다.하지만 이것을 수행하는 더 깨끗한 방법이 있어야합니다.

답변

1

이 유형의 문제는 LINQ가 C# 및 VB.NET에 도입 된 이유 중 좋은 예입니다. .NET 3.5 이상에서는 LINQ가이 문제를 해결하기 위해 찾고있는 "더 깨끗한 방법"을 제공합니다.

.NET 2.0을 사용하기 때문에 불행히도 "수동"방식으로 문제를 해결할 수 있습니다. 그러나 찾고있는 기능을 잘 정의 된 클래스 및 메서드로 캡슐화하여 깨끗한 코드를 작성할 수 있습니다. 이것은 LINQ의 이점 중 하나 (그러나 그 중 하나만은 아닙니다)입니다. 즉, 깨끗하고 선언적으로 기대되는 기능을 캡슐화합니다.

여기에 당신이 시작하는 몇 가지 예제 코드입니다 :

'The AggregateItem and AggregateItems classes will help encapsulate the ' 
'the functionality you are looking for.' 

Public Class AggregateItem 
    Public Property GroupByProperty1 As Integer ' Get/Set code...' 
    Public Property GroupByProperty2 As Integer ' Get/Set code...' 
    Public Property Values As List(Of Double) = New List(Of Double()() _ 
     ' Get/Set code...' 

    Public Function GetAverage() As Double 
     'Code to calculate and return Average...' 
    End Function  
End Class 

Public Class AggregateItems 
    Public Property AggregateItemList As List(Of AggregateItem) = _ 
     New List(Of AggregateItem)() ' Get/Set code...' 

    Public Sub InsertAggregateItem(groupByProperty1 As Integer, _ 
            groupByProperty2 As Integer, _ 
            value As Double) 
     Dim aiExisting As AggregateItem 
     aiExisting = GetMatchingAggregateItem(groupByProperty1, _ 
               groupByProperty2) 
     If Not aiExisting Is Nothing Then 
      aiExisting.Values.Add(value) 
     Else 
      aiExisting = New AggregateItem 
      aiExisting.GroupByProperty1 = groupByProperty1 
      aiExisting.GroupByProperty2 = groupByProperty2 
      aiExisting.Values.Add(value) 
      AggregateItemList.Add(aiExisting) 
    End Sub 

    Private Function GetMatchingAggregateItem(groupByProperty1 As Integer, _ 
               groupByProperty2 As Integer) _ 
      As AggregateItem 
     Dim aiMatch As AggregateItem = Nothing 
     For Each ag As AggregateItem in AggregateItemList 
      If ag.GroupByProperty1 = groupByProperty1 AndAlso _ 
       ag.GroupByProperty2 = groupByProperty2 Then 
       aiMatch = ag 
       Exit For 
      End If 
     Next 

     Return aiMatch 
    End Function 
Enc Class 

'Then, to consume these classes....' 

Public Module MyProgram 
    Public Sub Main() 
     Dim aItems As New AggregateItems() 
     'Say you have List(Of Order) named listOfOrders' 
     'We will loop through that list, insert the grouping IDs and values' 
     'into our AggregateItems object' 
     For Each o As Order In listOfOrders 
      aItems.InsertAggregateItem(o.OrderId, o.ProductId, o.ProductCount) 
     Next 

     'Now we can loop through aItems to cleanly get the average: ' 
     For Each ai As AggregateItem in aItems.AggregateItemsList 
      Console.WriteLine("Order: {0} Product: {1} Average: {2}", _ 
       ai.GroupByProperty1, ai.GroupByProperty2, _ 
       ai.GetAverage()) 
     Next 
    End Sub 

End Module 

잘 캡슐화 된 클래스로 데이터를 삽입하는 방법에 대한 좋은 점은 소비 코드가 매우 간결하고 이해하기 쉽다는 점이다. 또한 이미 데이터를 AggregateItem 클래스로 집계 했으므로 GetSum() 또는 GetMax()과 같은 더 많은 메소드로 클래스를 쉽게 확장 할 수 있습니다.

분명히 코드에서 더 나은 재사용을 위해이 추상화 과정을 계속할 수는 있지만 좋은 시작이라고 생각합니다.

+0

Thanx Ben. 데이터를 집계하지 않아도되었으므로 나중에 다른 방법으로 appz를 3.5로 업그레이드 할 예정이므로 다른 방법으로 접근 할 것입니다. 귀하의 솔루션은 내가 가진 비슷한 문제! :) – Mcad001

+0

@Mcad 업그레이드 중이라고 들었습니다. 팀에 4 할 계획을 세우고 4.0으로 업그레이드 할 수있는 기회가 있다고 생각하지 않습니까? –

관련 문제