LINQ - Basic Set Theory




Overview

This example focuses on basic set theory. The .Net Framework has several applicable LINQ extension methods, which can be easily used for determining four functions in basic set theory. These are...



This is a simple application requiring minimal coding. The code is annotated throughout, with the Operations Class having more detailed annotations.


Figure 1.0 - The Form at runtime



The SetInput UserControl

Figure 1.1 - The UserControl


This control encapsulates adding to or removing from a set of text items. It has a method to clear all of your input, and a function that returns your set as an array of Strings. This is a neat way for dealing with sets as a UserControl acts as an information specialist and avoids duplicating code.

Public Class SetInput
 
    'custom event
    Public Event contentChanged()
    Dim cms As New ContextMenuStrip
 
    'sets label text
    Public WriteOnly Property SetID As String
        Set(value As String)
            lblTitle.Text = "Set " & value
        End Set
    End Property
 
    'returns set size
    Public ReadOnly Property setLength() As Integer
        Get
            Return lstDisplay.Items.Count
        End Get
    End Property
 
    'sets up the ContextMenuStrip for the ListBox
    Private Sub SetInput_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        cms.Items.Add("Remove item", Nothing, AddressOf removeItem)
        RaiseEvent contentChanged()
    End Sub
 
    'paints title background
    Private Sub SetInput_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
        e.Graphics.FillRectangle(SystemBrushes.ControlDark, New Rectangle(0, 0, Me.Width, 23))
    End Sub
 
    'tests if item exists in set, if not it adds it to the set
    Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
        If lstDisplay.Items.Contains(txtInput.Text) Then
            inputErrorProvider.SetError(txtInput, "Set contains '" & txtInput.Text & "'")
        Else
            lstDisplay.Items.Add(txtInput.Text)
            RaiseEvent contentChanged()
            txtInput.Clear()
        End If
    End Sub
 
    'clears the ErrorProvider
    Private Sub txtInput_TextChanged(sender As Object, e As EventArgs) Handles txtInput.TextChanged
        inputErrorProvider.Clear()
    End Sub
 
    'enables Enter-Button press
    Private Sub txtInput_KeyDown(sender As Object, e As KeyEventArgs) Handles txtInput.KeyDown
        If e.KeyCode = Keys.Enter Then btnAdd.PerformClick()
    End Sub
 
    'only shows ContextMenuStrip if an item is selected in the ListBox
    Private Sub lstDisplay_SelectedIndexChanged(sender As Object, e As EventArgs) Handles lstDisplay.SelectedIndexChanged
        If lstDisplay.SelectedIndex <> -1 Then
            lstDisplay.ContextMenuStrip = cms
        Else
            lstDisplay.ContextMenuStrip = Nothing
        End If
    End Sub
 
    'MenuItem click eventhandler. Removes list item
    Private Sub removeItem(sender As Object, e As EventArgs)
        If lstDisplay.SelectedIndex <> -1 Then
            lstDisplay.Items.RemoveAt(lstDisplay.SelectedIndex)
            RaiseEvent contentChanged()
        End If
    End Sub
 
    'Control clear method. Clears any input
    Public Sub clear()
        inputErrorProvider.Clear()
        lstDisplay.Items.Clear()
        txtInput.Clear()
    End Sub
 
    'Returns set items
    Public Function getSet() As String()
        Return lstDisplay.Items.Cast(Of String).ToArray
    End Function
 
End Class


The Form

The Form is the container for the GUI, which consists of two SetInput UserControls, a ComboBox, a ListBox, and two Buttons. The Form code is fairly simple and annotated throughout.

Public Class frmExample
 
    Dim functions As New Dictionary(Of Integer, [Delegate])
    Dim operations As New Operations
 
    'app initializing
    Private Sub frmExample_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        SetInput1.SetID = "A"
        SetInput2.SetID = "B"
        cboChoice.SelectedIndex = 0
 
        functions.Add(1, New Func(Of String(), String(), String())(AddressOf operations.union))
        functions.Add(2, New Func(Of String(), String(), String())(AddressOf operations.intersection))
        functions.Add(3, New Func(Of String(), String(), String())(AddressOf operations.complement))
        functions.Add(4, New Func(Of String(), String(), String())(AddressOf operations.cartesianProduct))
 
    End Sub
 
    'clears any input
    Private Sub btnClear_Click(sender As Object, e As EventArgs) Handles btnClear.Click
        SetInput1.clear()
        SetInput2.clear()
        If cboChoice.SelectedIndex > 0 Then lstResults.Items.Clear()
        setEnabled()
    End Sub
 
    'changes btnClear.Enabled if necessary
    Private Sub setEnabled()
        btnClear.Enabled = SetInput1.setLength + SetInput2.setLength + lstResults.Items.Count + If(cboChoice.SelectedIndex = 0, -1, 0) > 0
    End Sub
 
    'adds results from selected function to lstResults
    Private Sub btnCompute_Click(sender As Object, e As EventArgs) Handles btnCompute.Click
        lstResults.Items.Clear()
        lstResults.Items.AddRange(DirectCast(functions(cboChoice.SelectedIndex).DynamicInvoke(SetInput1.getSet, SetInput2.getSet), String()))
        setEnabled()
    End Sub
 
    'sets some gui properties
    Private Sub cboChoice_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cboChoice.SelectedIndexChanged
        lstResults.Items.Clear()
        If cboChoice.SelectedIndex = 0 Then lstResults.Items.Add("No operation selected")
        btnCompute.Enabled = cboChoice.SelectedIndex > 0
    End Sub
 
    'Calls setEnabled(), which changes btnClear.Enabled if necessary
    Private Sub SetInput1_contentChanged() Handles SetInput1.contentChanged, SetInput2.contentChanged
        setEnabled()
    End Sub
 
End Class


The Operations Class

This Class contains just four functions, all of which take two String array arguments, and return a String array. These four functions correspond to the four set theory functions mentioned in the overview. Using LINQ, these really are one-liners, but they produce the required results.

Public Class Operations
 
    'error message
    Dim errortext() As String = New String() {"Insufficient data"}
 
    ''' <summary>
    ''' union Function
    ''' </summary>
    ''' <param name="setA"></param>
    ''' <param name="setB"></param>
    ''' <returns>with two inputs {1, 2} and {2, 3} returns {1, 2, 3}</returns>
    Public Function union(setA() As String, setB() As String) As String()
        Return If(setA.Count <> 0 Or setB.Count <> 0, setA.Union(setB).ToArray, errortext)
    End Function
 
    ''' <summary>
    ''' intersection Function
    ''' </summary>
    ''' <param name="setA"></param>
    ''' <param name="setB"></param>
    ''' <returns>with two inputs {1, 2} and {2, 3} returns {2} as both arrays contain 2</returns>
    Public Function intersection(setA() As String, setB() As String) As String()
        Return If(setA.Count <> 0 And setB.Count <> 0, setA.Intersect(setB).ToArray, errortext)
    End Function
 
    ''' <summary>
    ''' complement Function
    ''' </summary>
    ''' <param name="setA"></param>
    ''' <param name="setB"></param>
    ''' <returns>with two inputs {1, 2} and {2, 3} returns {1} as 1 is the only
    '''                 number in array1 that doesn't exist in array2</returns>
    Public Function complement(setA() As String, setB() As String) As String()
        Return If(setA.Count > 0 And setB.Count <> 0, setA.Except(setB).ToArray, errortext)
    End Function
 
    ''' <summary>
    ''' cartesianProduct Function
    ''' </summary>
    ''' <param name="setA"></param>
    ''' <param name="setB"></param>
    ''' <returns>with two inputs {1, 2} and {apple, orange} returns {(1, apple), (1, orange), (2, apple), (2, orange)}</returns>
    Public Function cartesianProduct(setA() As String, setB() As String) As String()
        Return If(setA.Count <> 0 And setB.Count <> 0, setA.SelectMany(Function(x) setB.Select(Function(y) "(" & x & ", " & y & ")")).ToArray, errortext)
    End Function
 
End Class

Conclusion

This example shows some LINQ methods, but more importantly, shows how to create reusable UserControls for data input, editing, and display.



You can download the example project here





Try it now...