none
Check if a custom list (of x) contains an item before adding it RRS feed

  • Question

  • Hi all

    I have a custom class to store some information e.g.

    Public Class Jobs    
       Public Property _Source As String    
       Public Property _Destination As String
    End Class

    I am adding to it like below, but I want to check first to make sure the _Source  I am adding doesn't already exist

    Dim JobList As New List(Of Jobs)()
    
    Dim _JI As New Jobs
    _JI._Source = My.Computer.FileSystem.SpecialDirectories.MyPictures
    _JI._Destination = "c:\test"
    JobList.Add(_JI)

    Normally I would use 'If Not JobList.Contains("") Then' but this doesn't seem to work with a list of my own class

    Am I missing something obvious or is there a better way to achieve this?

    Thanks


    Darren Rose

    Friday, April 3, 2020 3:52 PM

Answers

  • Hi

    Here is some code based on MS examples.

    It uses your example, then tries to add an identical item but fails as it is already in the lisy. then adds a different item just to prove that works too.

    Option Strict On
    Option Explicit On
    Public Class Form1
      Dim JobList As New List(Of Jobs)
    
      Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    
        ' your example
        Dim _JI As New Jobs
        _JI._Source = My.Computer.FileSystem.SpecialDirectories.MyPictures
        _JI._Destination = "c:\test"
        JobList.Add(_JI)
    
        ' try to add identical item
        ' should fail to add as already
        ' in th list
        Dim _JI2 As New Jobs
        _JI2._Source = My.Computer.FileSystem.SpecialDirectories.MyPictures
        _JI2._Destination = "c:\test"
        If Not JobList.Contains(_JI2) Then JobList.Add(_JI2)
    
        ' try to add different item
        ' should succeed as not in list
        Dim _JI3 As New Jobs
        _JI3._Source = My.Computer.FileSystem.SpecialDirectories.MyPictures
        _JI3._Destination = "c:\test2"
        If Not JobList.Contains(_JI3) Then JobList.Add(_JI3)
    
    
        ' count items - should be = 2 if .Contains obeyed
        Dim c As Integer = JobList.Count
        ' hover over c and find if = 2
        ' if = 2 then the .Contains worked
    
        ' hover over JobList and examine
        ' items in the list.
        Stop
      End Sub
      Public Class Jobs
        Implements IEquatable(Of Jobs)
        Public Property _Source As String
        Public Property _Destination As String
    
        Public Overloads Function Equals(ByVal other As Jobs) As Boolean Implements IEquatable(Of Jobs).Equals
          If Me._Source = other._Source And Me._Destination = other._Destination Then
            Return True
          Else
            Return False
          End If
        End Function
      End Class
    End Class


    Regards Les, Livingston, Scotland

    • Marked as answer by wingers Wednesday, May 6, 2020 4:58 PM
    Friday, April 3, 2020 4:33 PM
  • Hello Darren,

    Perhaps taking a different direction, add all items then with your class implementing IEqualityComparer pass a customer comparer to Distinct method.

    Example I want distinct by company name and country.

    Customer (slimmed down), ignore INotifyPropertyChanged

    Imports System.ComponentModel
    Imports System.Runtime.CompilerServices
    Imports JetBrains.Annotations
    
    Namespace Classes
        Public Class Customer
            Implements INotifyPropertyChanged
    
            Private _companyName As String
            Private _country As String
    
            Public Property CustomerIdentifier() As Integer
            ''' <summary>
            ''' Name of company - can not be null
            ''' </summary>
            ''' <returns></returns>
            Public Property CompanyName() As String
                Get
                    Return _companyName
                End Get
                Set
    
                    If Value = _companyName Then
                        Return
                    End If
    
                    _companyName = Value
                    OnPropertyChanged()
    
                End Set
            End Property
            ''' <summary>
            ''' Country name
            ''' </summary>
            ''' <returns></returns>
            Public Property Country() As String
                Get
                    Return _country
                End Get
                Set
                    If Value = _country Then
                        Return
                    End If
    
                    _country = Value
                    OnPropertyChanged()
    
                End Set
            End Property
    
            Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
    
            <NotifyPropertyChangedInvocator>
            Protected Overridable Sub OnPropertyChanged(<CallerMemberName> Optional ByVal propertyName As String = Nothing)
                PropertyChangedEvent?.Invoke(Me, New PropertyChangedEventArgs(propertyName))
            End Sub
    
        End Class
    
    End Namespace
    

    Custom Comparer

    Namespace Classes
    
        Public Class CustomerNameCountryComparer
            Implements IEqualityComparer(Of Customer)
    
            Public Overloads Function Equals(
                customer1 As Customer,
                customer2 As Customer) As Boolean _
                Implements IEqualityComparer(Of Customer).Equals
    
                Return customer1.CompanyName = customer2.CompanyName AndAlso customer1.Country = customer2.Country
    
            End Function
    
            Public Overloads Function GetHashCode(customer As Customer) As Integer _
                Implements IEqualityComparer(Of Customer).GetHashCode
    
                Return New With {
                    Key customer.CompanyName,
                    Key customer.Country
                    }.GetHashCode()
    
            End Function
    
        End Class
    
    End Namespace

    Mocked data

    Namespace Classes
        Public Class MockedData
            Public Shared Function CustomerList() As List(Of Customer)
    
                Return New List(Of Customer)() From {
                    New Customer() With {.CompanyName = "Parfropanicator  Corp", .Country = "Namibia"},
                    New Customer() With {.CompanyName = "Winsipazz WorldWide", .Country = "Australia"},
                    New Customer() With {.CompanyName = "Parfropanicator  Corp", .Country = "Vanuatu"},
                    New Customer() With {.CompanyName = "Parfropanicator  Corp", .Country = "Vanuatu"},
                    New Customer() With {.CompanyName = "Winsipazz WorldWide", .Country = "Australia"},
                    New Customer() With {.CompanyName = "Parpickazz Direct Group", .Country = "USA"}}
    
            End Function
        End Class
    End Namespace

    Example

    Module Program
        Sub Main(args As String())
    
            Dim customers = MockedData.CustomerList().
                    Distinct(New CustomerNameCountryComparer).
                    OrderBy(Function(customer) customer.CompanyName)
    
            For Each customer As Customer In customers
                Console.WriteLine($"  {customer.CompanyName,-25}|{customer.Country}")
            Next
    
            Console.WriteLine()
            Console.WriteLine("Press a key to quit")
            Console.ReadLine()
        End Sub
    End Module


    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    • Marked as answer by wingers Wednesday, May 6, 2020 4:58 PM
    Friday, April 3, 2020 4:42 PM
    Moderator

All replies

  • Hi Darren,

    I think you are searching for the sorted list which is probably better to use for Steve.

    https://docs.microsoft.com/en-us/dotnet/api/system.collections.sortedlist?view=netframework-4.8


    Success
    Cor

    Friday, April 3, 2020 4:07 PM
  • Hi,
    for objects contains compare references to the same object.

    For demonstration try following demo:

    Module Module44
    
      Sub Main()
        Try
          Call (New Demo).Execute()
        Catch ex As Exception
          Console.WriteLine(ex.ToString)
        End Try
        Console.WriteLine("Continue enter key")
        Console.ReadKey()
      End Sub
    
    
      Friend Class Demo
    
        Private JobList As New List(Of Jobs)()
    
        Friend Sub Execute()
          ' add new Jobs
          For i = 1 To 9
            JobList.Add(New Jobs With {._Source = $"Source{i}", ._Destination = $"Destination {i}"})
          Next
          ' test contains
          Dim j1 As New Jobs With {._Source = $"Source5", ._Destination = $"Destination 5"}
          Dim res1 = JobList.Contains(j1) ' must be false
          Console.WriteLine($"Contains {res1}")
          Dim j2 = JobList(4)
          Console.WriteLine($"j1 Source {j1._Source}, j2 Source {j2._Source}")
          Dim res2 = j1.Equals(j2)
          Console.WriteLine($"Equal {res2}")
          Dim j3 = JobList.FirstOrDefault(New Func(Of Jobs, Boolean)(Function(j) As Boolean
                                                                       Return j._Source = "Source5"
                                                                     End Function))
          Dim res3 = j3 IsNot Nothing ' must be true
          Console.WriteLine($"FirstOrDefault {res3}")
        End Sub
    
      End Class
      Public Class Jobs
        Public Property _Source As String
        Public Property _Destination As String
      End Class
    
    End Module


    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks


    Friday, April 3, 2020 4:12 PM

  • I have a custom class to store some information e.g.

    Public Class Jobs    
       Public Property _Source As String    
       Public Property _Destination As String
    End Class

    Normally I would use 'If Not JobList.Contains("") Then' but this doesn't seem to work with a list of my own class


    If you look at the example here:

    List<T>.Contains(T) Method
    https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.contains?view=netframework-4.8

    you will see how List Contains can be made to work with a custom class.

    The code is in C# but you should get the idea of how to do it in Basic as well.

    - Wayne

    Friday, April 3, 2020 4:17 PM
  • Hi Darren,

    I think you are searching for the sorted list which is probably better to use for Steve.

    https://docs.microsoft.com/en-us/dotnet/api/system.collections.sortedlist?view=netframework-4.8


    Success
    Cor

    My class will contain more than two propetties, I just put two in example to lessen code, but it will contain 5 or 6 initially, and sorted list looks like only for key / pair values unless I am missing something?

    Darren Rose

    Friday, April 3, 2020 4:29 PM
  • Hi

    Here is some code based on MS examples.

    It uses your example, then tries to add an identical item but fails as it is already in the lisy. then adds a different item just to prove that works too.

    Option Strict On
    Option Explicit On
    Public Class Form1
      Dim JobList As New List(Of Jobs)
    
      Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    
        ' your example
        Dim _JI As New Jobs
        _JI._Source = My.Computer.FileSystem.SpecialDirectories.MyPictures
        _JI._Destination = "c:\test"
        JobList.Add(_JI)
    
        ' try to add identical item
        ' should fail to add as already
        ' in th list
        Dim _JI2 As New Jobs
        _JI2._Source = My.Computer.FileSystem.SpecialDirectories.MyPictures
        _JI2._Destination = "c:\test"
        If Not JobList.Contains(_JI2) Then JobList.Add(_JI2)
    
        ' try to add different item
        ' should succeed as not in list
        Dim _JI3 As New Jobs
        _JI3._Source = My.Computer.FileSystem.SpecialDirectories.MyPictures
        _JI3._Destination = "c:\test2"
        If Not JobList.Contains(_JI3) Then JobList.Add(_JI3)
    
    
        ' count items - should be = 2 if .Contains obeyed
        Dim c As Integer = JobList.Count
        ' hover over c and find if = 2
        ' if = 2 then the .Contains worked
    
        ' hover over JobList and examine
        ' items in the list.
        Stop
      End Sub
      Public Class Jobs
        Implements IEquatable(Of Jobs)
        Public Property _Source As String
        Public Property _Destination As String
    
        Public Overloads Function Equals(ByVal other As Jobs) As Boolean Implements IEquatable(Of Jobs).Equals
          If Me._Source = other._Source And Me._Destination = other._Destination Then
            Return True
          Else
            Return False
          End If
        End Function
      End Class
    End Class


    Regards Les, Livingston, Scotland

    • Marked as answer by wingers Wednesday, May 6, 2020 4:58 PM
    Friday, April 3, 2020 4:33 PM
  • @WayneAKing, @Peter Fleischer, @Cor Ligthert

    Thank you for all your answers, I will have a look at them and see which works best for me


    Darren Rose

    Friday, April 3, 2020 4:40 PM
  • Hi

    Here is some code based on MS examples.

    It uses your example, then tries to add an identical item but fails as it is already in the lisy. then adds a different item just to prove that works too.

    Thanks Les, will give it a try :)

    Darren Rose

    Friday, April 3, 2020 4:40 PM
  • Hello Darren,

    Perhaps taking a different direction, add all items then with your class implementing IEqualityComparer pass a customer comparer to Distinct method.

    Example I want distinct by company name and country.

    Customer (slimmed down), ignore INotifyPropertyChanged

    Imports System.ComponentModel
    Imports System.Runtime.CompilerServices
    Imports JetBrains.Annotations
    
    Namespace Classes
        Public Class Customer
            Implements INotifyPropertyChanged
    
            Private _companyName As String
            Private _country As String
    
            Public Property CustomerIdentifier() As Integer
            ''' <summary>
            ''' Name of company - can not be null
            ''' </summary>
            ''' <returns></returns>
            Public Property CompanyName() As String
                Get
                    Return _companyName
                End Get
                Set
    
                    If Value = _companyName Then
                        Return
                    End If
    
                    _companyName = Value
                    OnPropertyChanged()
    
                End Set
            End Property
            ''' <summary>
            ''' Country name
            ''' </summary>
            ''' <returns></returns>
            Public Property Country() As String
                Get
                    Return _country
                End Get
                Set
                    If Value = _country Then
                        Return
                    End If
    
                    _country = Value
                    OnPropertyChanged()
    
                End Set
            End Property
    
            Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
    
            <NotifyPropertyChangedInvocator>
            Protected Overridable Sub OnPropertyChanged(<CallerMemberName> Optional ByVal propertyName As String = Nothing)
                PropertyChangedEvent?.Invoke(Me, New PropertyChangedEventArgs(propertyName))
            End Sub
    
        End Class
    
    End Namespace
    

    Custom Comparer

    Namespace Classes
    
        Public Class CustomerNameCountryComparer
            Implements IEqualityComparer(Of Customer)
    
            Public Overloads Function Equals(
                customer1 As Customer,
                customer2 As Customer) As Boolean _
                Implements IEqualityComparer(Of Customer).Equals
    
                Return customer1.CompanyName = customer2.CompanyName AndAlso customer1.Country = customer2.Country
    
            End Function
    
            Public Overloads Function GetHashCode(customer As Customer) As Integer _
                Implements IEqualityComparer(Of Customer).GetHashCode
    
                Return New With {
                    Key customer.CompanyName,
                    Key customer.Country
                    }.GetHashCode()
    
            End Function
    
        End Class
    
    End Namespace

    Mocked data

    Namespace Classes
        Public Class MockedData
            Public Shared Function CustomerList() As List(Of Customer)
    
                Return New List(Of Customer)() From {
                    New Customer() With {.CompanyName = "Parfropanicator  Corp", .Country = "Namibia"},
                    New Customer() With {.CompanyName = "Winsipazz WorldWide", .Country = "Australia"},
                    New Customer() With {.CompanyName = "Parfropanicator  Corp", .Country = "Vanuatu"},
                    New Customer() With {.CompanyName = "Parfropanicator  Corp", .Country = "Vanuatu"},
                    New Customer() With {.CompanyName = "Winsipazz WorldWide", .Country = "Australia"},
                    New Customer() With {.CompanyName = "Parpickazz Direct Group", .Country = "USA"}}
    
            End Function
        End Class
    End Namespace

    Example

    Module Program
        Sub Main(args As String())
    
            Dim customers = MockedData.CustomerList().
                    Distinct(New CustomerNameCountryComparer).
                    OrderBy(Function(customer) customer.CompanyName)
    
            For Each customer As Customer In customers
                Console.WriteLine($"  {customer.CompanyName,-25}|{customer.Country}")
            Next
    
            Console.WriteLine()
            Console.WriteLine("Press a key to quit")
            Console.ReadLine()
        End Sub
    End Module


    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    • Marked as answer by wingers Wednesday, May 6, 2020 4:58 PM
    Friday, April 3, 2020 4:42 PM
    Moderator
  • Sorry for long delay in replying here - life got in the way!

    Thank you all for your input which helped greatly


    Darren Rose

    Wednesday, May 6, 2020 4:58 PM