forX
forX

Reputation: 2153

vb.net linq list of object

In vb.net, using linq, join 2 list of object. Both list are the same type.

I search the best way to concat both list grouping by Id. Like a Distinct.

Sample :

Imports System.Text
Imports System.Reflection

Module Module1

    Sub Main()
        Dim list1 As New List(Of Item)
        For i As Integer = 1 To 4
            list1.Add(New Item(i, i.ToString))
        Next

        Dim list2 As New List(Of Item)
        For i As Integer = 3 To 6
            list2.Add(New Item(i, i.ToString))
        Next

        Dim list3 As New List(Of Item)
        list3 = (list1.Concat(list2)).ToList
        Console.WriteLine(Item.PrintList(list3).ToString)        

        Console.ReadLine()
    End Sub

End Module

Class Item
    Private _Id As Integer
    Private _Value As String

    Public Property Id() As Integer
        Get
            Return _Id
        End Get
        Set(ByVal value As Integer)
            _Id = value
        End Set
    End Property
    Public Property Value() As String
        Get
            Return _Value
        End Get
        Set(ByVal value As String)
            _Value = value
        End Set
    End Property

    Public Sub New()
    End Sub
    Public Sub New(ByVal id As Integer, ByVal value As String)
        Me.Id = id
        Me.Value = value
    End Sub

    Public Overrides Function ToString() As String
        Dim sb = New Text.StringBuilder()        
        For Each item In [GetType]().GetFields(BindingFlags.NonPublic Or BindingFlags.Instance)
            sb.Append(String.Format("[{0} = {1}] ", item.Name, item.GetValue(Me)))
        Next
        Return sb.ToString()
    End Function

    Public Shared Function PrintList(ByVal myList As List(Of Item)) As StringBuilder
        Dim result As New StringBuilder
        For Each i In myList
            result.AppendLine(i.ToString)
        Next
        Return result
    End Function

End Class

What the list3 contain after concat :

[_Id = 1] [_Value = 1] 
[_Id = 2] [_Value = 2] 
[_Id = 3] [_Value = 3] 
[_Id = 4] [_Value = 4] 
[_Id = 3] [_Value = 3] 
[_Id = 4] [_Value = 4] 
[_Id = 5] [_Value = 5] 
[_Id = 6] [_Value = 6] 

What we want :

[_Id = 1] [_Value = 1] 
[_Id = 2] [_Value = 2] 
[_Id = 3] [_Value = 3] 
[_Id = 4] [_Value = 4] 
[_Id = 5] [_Value = 5] 
[_Id = 6] [_Value = 6] 

Upvotes: 2

Views: 1631

Answers (2)

Stefan
Stefan

Reputation: 11509

With the addition of Equals and GetHashCode in Tim Schmelter answer, you now also have the possibility to use Concat and .Distinct directly on the Query:

Dim list3 As List(Of Item) = list1.Concat(list2).Distinct.ToList

or using where and distinct in the query:

Dim list3 As List(Of Item) = (From data In list1.Concat(list2) Where data.Value = "MyCity" Distinct).ToList

variation:

  Dim list3 As List(Of Item) = (From data In list1.Concat(list2) Where data.Value = "MyCity").Distinct.ToList

Upvotes: 1

Tim Schmelter
Tim Schmelter

Reputation: 460138

I search the best way to concat both list grouping by Id. Like a Distinct.

Use Enumerable.Union.

However, you need to override Equals and GetHashCode in the class Item first. Then all Linq methods will use your ID:

Class Item
    Public Property ID As Int32

    Public Overrides Function Equals(obj As Object) As Boolean
        If obj Is Nothing Then Return False
        If Not TypeOf obj Is Item Then Return False
        Return Id = DirectCast(obj, Item).Id
    End Function

    Public Overrides Function GetHashCode() As Integer
        Return Id.GetHashCode()
    End Function
End Class

Now you can use Union which is efficient and clear:

Dim list3 = list1.Union(list2).ToList

MSDN:

This method excludes duplicates from the return set. This is different behavior to the Concat<TSource> method, which returns all the elements in the input sequences including duplicates. ... To compare a custom data type, you need to implement this interface and provide your own GetHashCode and Equals methods for the type.

Upvotes: 4

Related Questions