Lambda Expressions

An Introduction

Another thing that I like about programming in .NET beyond LINQ and Extensions is lambda expressions. (It should be noted that LINQ, Extensions, and lambda expressions are all related). Lambda expressions are “are callable entities that are defined within a function, you can return a lambda expression from a function and you can pass lambda expressions to other functions.” Lambda expressions come with the System.Core library, so no need to add a reference nor Imports at the top of your class.

Lambda expressions simplify your code by allowing you to call internal functions within functions, even create “function variables.” To get a full overview read the link on lambda expressions.

Let’s take the extension examples I used before, but simplify it with lambda expressions. Before I had to create multiple private functions to accommodate different comparison types (e.g., String, Double, Object, etc). But with lambda expressions I can create local functions that take care of this, which lessons the amount of code and makes the code cleaner.

So let’s dive into some code. First I needed to create a delegate function which accepts multiple types of input and returns an integer.

Delegate Function MoreLessOrEqual(Of T)(ByVal element As T) As Integer

I then created a pointer function which determines which internal function I should use depending on what type of data is received. Notice the lambda expressions written as Function(a As Object)….

<Extension()>
Public Function FindIndex2DSorted(ByRef oaArray(,) As Object, ByVal oWhat As Object _
                                  , Optional ByVal iSearchIndex As Integer = 0 _
                                  , Optional ByVal eStringCompare _
                                  As StringComparison = StringComparison.CurrentCulture) As Integer

    If TypeOf oWhat Is Double Then  'Use double type comparison.
        Dim dWhat As Double = CDbl(oWhat)
        Return FindIndex2DSortedLambda(oaArray, Function(a As Object) If(CDbl(a) > dWhat, -1, If(CDbl(a) = dWhat, 0, 1)) _
                                , iSearchIndex)
    ElseIf TypeOf oWhat Is String Then  'Use string type comparison.
        Dim sWhat As String = oWhat.ToString
        Return FindIndex2DSortedLambda(oaArray, Function(a As Object) String.Compare(CStr(a), sWhat, eStringCompare) _
                                , iSearchIndex)
    Else    'Not set up for other types of data.
        Return -1
    End If

End Function

In this private function I call the lambda expressions as defined in the function parameters as IsEqual.

Private Function FindIndex2DSortedLambda(ByVal oaArray As Object(,), ByVal IsEqual As MoreLessOrEqual(Of Object) _
                            , ByVal iSearchIndex As Integer) As Integer                                                            

    Dim i As Integer, lUpperSearch As Integer, lLowerSearch As Integer, lPrevious As Integer, lNext As Integer

    lUpperSearch = oaArray.GetUpperBound(0) : lLowerSearch = 0 : lPrevious = -1

    If IsEqual(oaArray(0, iSearchIndex)) < 0 Then 'If value is the less than the first index then skip
        Return -1
    ElseIf IsEqual(oaArray(lUpperSearch, iSearchIndex)) > 0 Then 'If it is greater than the last index then skip
        Return -3
    Else
        i = -1
    End If

    'Find start indexes
    Dim iResult As Integer
    Do While i = -1
        lNext = (lUpperSearch + lLowerSearch) \ 2 'Get new search location
        iResult = IsEqual(oaArray(lNext, iSearchIndex))
        If iResult > 0 Then 'Get new lower search location
            lLowerSearch = lNext
        ElseIf iResult < 0 Then 'Get new upper search location
            lUpperSearch = lNext
        Else 'If equal find first instance of item
            i = lNext - 1
            Do While IsEqual(oaArray(i, iSearchIndex)) = 0
                i -= 1
            Loop
            i += 1
        End If
        If lPrevious = lNext Then 'Get first item
            For i = lLowerSearch To lUpperSearch
                If IsEqual(oaArray(i, iSearchIndex)) = 0 Then
                    Return i
                End If
            Next
            Return -2
        Else
            lPrevious = lNext
        End If
    Loop

    Return i

End Function

Note that I could make the private function the a public extension. By doing that I could then easily create more elaborate searches, e.g., I could search for the index of a string with the first three letters equal to “ABC” like below.

Dim sWhat As String = oWhat.ToString.Substring(0, 3)
Return FindIndex2DSortedLambda(oaArray, Function(a As Object) String.Compare(a.ToString.Substring(0, 3), sWhat, eStringCompare) _
    , iSearchIndex)