Search code examples
vb.neticomparersorteddictionary

Implementing iComparer for custom objects after converting a Dictionary to SortedDictionary


I'm having trouble implementing an IComparer method. Essentially, I want to compare the properties of two custom objects (the properties are of type integer).

dE is a Dictionary(Of String, customObj) prTabIndex is a property of customObj and is of type Integer (these hold true for all examples)

After some more searching I found this thread which suggested 3 things: a List approach, utilizing LINQ, and using some C# 3.0 features. However, being in vb, not sure what they best approach is.

I've tried three different ways:

...rolling my own IComparer implementation:

Public m As Sub(ByRef d As Dictionary(of String, customObj))

   Dim sortedD As New SortedDictionary(Of String, customObj)(d, myCompare)

End Sub

 Public Class myCompare
     Implements IComparer

    Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements System.Collections.IComparer.Compare
        If TryCast(x, customObj).prTabIndex < TryCast(y, customObj).prTabIndex Then
            Return -1
        Else
            Return 1
        End If
    End Function
End Class


...Sorting a list (which, I think works - making this thread slightly academic).

Dim sortedL As List(Of KeyValuePair(Of String, customObj)) = dE.ToList
    sortedL.Sort(Function(firstPair As KeyValuePair(Of String, customObj), nextPair As KeyValuePair(Of String, customObj)) firstPair.Value.prTabIndex.CompareTo(nextPair.Value.prTabIndex))


...or incorporating the lambda function directly in the conversion to the SortedDictionary:

        Dim dESorted = From kvp As KeyValuePair(Of String, customObj) In dE.ToDictionary(Function(first As KeyValuePair(Of String, customObj), second As KeyValuePair(Of String, customObj)) first.Value.prTabIndex.CompareTo(nextPair.Value.prTabIndex))

Note that VS2008 has underlined 'dE.ToDictionary...' (to the end of the line) and giving me two messages depending on where I hover my mouse:

1) "Data type(s) of the type parameter(s) in extension method 'signature' As 'signature defined in 'System.Linq.Enumerable cannot be inferred from these arguments. Specifying the data types explicitly might correct this error. Seen while hovering over "ToDictionary".

2) Nested function does not have the same signature as delegate 'signature'. Seen while hovering over anything after "ToDictionary".

Admittedly, I'm new to lambda functions.

Q1) How far off am I in each of the implementations?

Q2) Which one is the computationally least expensive? Why?

Q3) Which one is the computationally most expensive? Why?

Warm Regards,

-sf


Solution

  • You can save your self casting if you implement the Generic IComparable(Of ...). I think you should also handle the possibility that the two objects are equal.

    Public Class DemoClass
      Implements IComparable(Of DemoClass)
    
      Private mstrField1 As String
      Public Property Field1() As String
        Get
          Return mstrField1
        End Get
        Set(ByVal value As String)
          mstrField1 = value
        End Set
      End Property
    
    
      Private mstrField2 As String
      Public Property Field2() As String
        Get
          Return mstrField2
        End Get
        Set(ByVal value As String)
          mstrField2 = value
        End Set
      End Property
    
      Private mstrField3 As String
      Public Property Field3() As String
        Get
          Return mstrField3
        End Get
        Set(ByVal value As String)
          mstrField3 = value
        End Set
      End Property
    
      ''' <summary>
      ''' Default sort - 1 ASC, 2 ASC, 3 ASC 
      ''' </summary>
      ''' <param name="other"></param>
      ''' <returns></returns>
      ''' <remarks></remarks>
      Public Function CompareTo(ByVal other As DemoClass) As Integer Implements System.IComparable(Of DemoClass).CompareTo
        '-1 = less than other; 0 = same as other; +1 = greater than other'
        Select Case Me.Field1
          Case Is < other.Field1 : Return -1
          Case Is > other.Field1 : Return 1
          Case Else 'equal
            Select Case Me.Field2
              Case Is < other.Field2 : Return -1
              Case Is > other.Field2 : Return 1
              Case Else 'equal
                Select Case Me.Field3
                  Case Is < other.Field3 : Return -1
                  Case Is > other.Field3 : Return 1
                  Case Else : Return 0 'equal
                End Select
            End Select
        End Select
      End Function
    End Class