Share via


C# - 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...

  • Unions
  • Intersections
  • Complements
  • Cartesian Products

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


The SetInput 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.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace Set_Theory_cs
{
    public partial  class SetInput : UserControl
    {
 
        //custom event
        public delegate  void contentChangedEventHandler();
        public event  contentChangedEventHandler contentChanged;
 
        private ContextMenuStrip cms = new ContextMenuStrip();
        private ErrorProvider inputErrorProvider = new ErrorProvider();
 
        //sets label text
        public string  SetID
        {
            set
            {
                lblTitle.Text = "Set " + value;
            }
        }
 
        //returns set size
        public int  setLength
        {
            get
            {
                return lstDisplay.Items.Count;
            }
        }
 
 
        //Constructor...sets up the ContextMenuStrip for the ListBox
        public SetInput()
        {
            InitializeComponent();
 
            cms.Items.Add("Remove item", null, removeItem);
            if (contentChanged != null) {contentChanged();}
 
            this.Paint += SetInput_Paint;
            txtInput.KeyDown += txtInput_KeyDown;
 
        }
 
        //paints title background
        private void  SetInput_Paint(object sender, PaintEventArgs e)
        {
            e.Graphics.FillRectangle(SystemBrushes.ControlDark, new  Rectangle(0, 0, this.Width, 23));
        }
 
        //tests if item exists in set, if not it adds it to the set
        private void  btnAdd_Click(object  sender, EventArgs e)
        {
            if (lstDisplay.Items.Contains(txtInput.Text))
            {
                inputErrorProvider.SetError(txtInput, "Set contains '"  + txtInput.Text + "'");
            }
            else
            {
                lstDisplay.Items.Add(txtInput.Text);
                if (contentChanged != null) { contentChanged();}
                txtInput.Clear();
            }
 
        }
 
        //clears the ErrorProvider
        private void  txtInput_TextChanged(object sender, EventArgs e)
        {
            inputErrorProvider.Clear();
 
        }
 
        //enables Enter-Button press
        private void  txtInput_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter) {btnAdd.PerformClick();}
        }
 
        //only shows ContextMenuStrip if an item is selected in the ListBox
        private void  lstDisplay_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (lstDisplay.SelectedIndex != -1)
            {
                lstDisplay.ContextMenuStrip = cms;
            }
            else
            {
                lstDisplay.ContextMenuStrip = null;
            }
 
        }
 
        //MenuItem click eventhandler. Removes list item
        private void  removeItem(object  sender, EventArgs e)
        {
            if (lstDisplay.SelectedIndex != -1)
            {
                lstDisplay.Items.RemoveAt(lstDisplay.SelectedIndex);
                if (contentChanged != null) {contentChanged();}
            }
        }
 
        //Control clear method. Clears any input
        public void  clear()
        {
            inputErrorProvider.Clear();
            lstDisplay.Items.Clear();
            txtInput.Clear();
        }
 
        //Returns set items
        public string[] getSet()
        {
            return lstDisplay.Items.Cast<string>().ToArray();
        }
 
    }
}

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.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace Set_Theory_cs
{
    public partial  class frmExample : Form
    {
 
        Dictionary<int, Delegate> functions = new  Dictionary<int, Delegate>();
        Operations operations = new  Operations();
 
        //adds some handlers
        public frmExample()
        {
            InitializeComponent();
 
            setInput1.contentChanged += SetInputs_contentChanged;
            setInput2.contentChanged += SetInputs_contentChanged;
        }
 
        //app initializing
        private void  frmExample_Load(object sender, EventArgs e)
        {
            setInput1.SetID = "A";
            setInput2.SetID = "B";
            cboChoice.SelectedIndex = 0;
 
            functions.Add(1, new  Func<string[], string[], string[]>(operations.union));
            functions.Add(2, new  Func<string[], string[], string[]>(operations.intersection));
            functions.Add(3, new  Func<string[], string[], string[]>(operations.complement));
            functions.Add(4, new  Func<string[], string[], string[]>(operations.cartesianProduct));
 
        }
 
        //clears any input
        private void  btnClear_Click(object sender, EventArgs e)
        {
            setInput1.clear();
            setInput2.clear();
            if (cboChoice.SelectedIndex > 0) {lstResults.Items.Clear();}
            setEnabled();
        }
 
        //changes btnClear.Enabled if necessary
        private void  setEnabled()
        {
            btnClear.Enabled = setInput1.setLength + setInput2.setLength + lstResults.Items.Count + ((cboChoice.SelectedIndex == 0) ? -1 : 0) > 0;
        }
 
        //adds results from selected function to lstResults
        private void  btnCompute_Click(object sender, EventArgs e)
        {
            lstResults.Items.Clear();
            lstResults.Items.AddRange((string[])(functions[cboChoice.SelectedIndex].DynamicInvoke(setInput1.getSet(), setInput2.getSet())));
            setEnabled();
        }
 
        //sets some gui properties
        private void  cboChoice_SelectedIndexChanged(object sender, EventArgs e)
        {
            lstResults.Items.Clear();
            if (cboChoice.SelectedIndex == 0) {lstResults.Items.Add("No operation selected");}
            btnCompute.Enabled = cboChoice.SelectedIndex > 0;
        }
 
        //Calls setEnabled(), which changes btnClear.Enabled if necessary
        private void  SetInputs_contentChanged()
        {
            setEnabled();
        }
 
    }
}

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.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace Set_Theory_cs
{
    public class  Operations
    {
        //error message
        private string[] errortext = 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 string[] union(string[] setA, string[] setB)
        {
            return ((setA.Count() != 0 | setB.Count() != 0) ? setA.Union(setB).ToArray() : errortext);
        }
 
        /// <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 string[] intersection(string[] setA, string[] setB)
        {
            return ((setA.Count() != 0 & setB.Count() != 0) ? setA.Intersect(setB).ToArray() : errortext);
        }
 
        /// <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 string[] complement(string[] setA, string[] setB)
        {
            return ((setA.Count() > 0 & setB.Count() != 0) ? setA.Except(setB).ToArray() : errortext);
        }
 
        /// <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 string[] cartesianProduct(string[] setA, string[] setB)
        {
            return ((setA.Count() != 0 & setB.Count() != 0) ? setA.SelectMany((x) => setB.Select((y) => "(" + x +  ", " + y + ")")).ToArray() : errortext);
        }
 
    }
 
}

Conclusion

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


See also

VB.Net version


Download 

Download here...