Home

F# Collections: A Set of Elements

 

Fundamentals of a Set

 

Introduction

A set is a collection of items called elements. The elements can be of any kind: numbers (naturals or decimals), strings (words, names, titles, sentences, etc), or objects (from classes).

 

 

In algebra, a set is usually represented with an uppercase letter, such as A, R, or W.

Creating a Set

To support sets, the F# language provides a module named Set. This module is included in the Microsoft.FSharp.Collections namespace.

To create a set in F#, you can use the set keyword. It is followed by []. Inside of them, create your list of elements. You have various options. The most fundamental or the easiest way to create a set is to create a list of values between [ and ] and separate them with semicolons. Here is an example:

set [ 2; 37; 4; 3774; 38; 74; 31 ]

As done for lists and arrays, each item can be written on its own line.

The values of a set can be of any kind, including a structure, a class, or a record. Here is an example that uses a record:

type ZoneInclusion = | Entirely | Split

type State = {
    Name      : string
    Inclusion : ZoneInclusion }

set [ { Name = "Maine"; Inclusion = Entirely }; { Name = "Michigan"; Inclusion = Split } ]

Instead of semicolons, you can separate the elements with commas. Here is an example:

set [ 20, 8, 93, 405, 3, 40 ]

If you do this, all of the items are considered as belonging to one (or a common) tuple. This means that the elements would be treated as a group.

If you want to use the set over and over again, declare a variable and initialize it with the set. Here is a example:

let series = set [ 20; 8; 93; 405; 8; 3; 40 ]

Accessing a Set

Because a set is primarily a list, it and its elements are accessed as done for a List. To access all elements as one, you can use the %A operator in the desired placeholder. Here is an example:

let names = set [ "Kevin"; "Jane"; "Daniel"; "Ruth"; "Paul" ]

lblNames.Text <- "Names: %A" names

To access each element of the set, you can use a for...in. Here is an example:

open System
open System.Drawing
open System.Windows.Forms 

let evaluations = set [ "True Positive"; "True Negative"; "False Positive"; "False Negative" ]

let classification = new Form(MaximizeBox = false, StartPosition = FormStartPosition.CenterScreen,
                              Text = "Classification", ClientSize = new System.Drawing.Size(175, 92)) 

let lbxClassifications = new ListBox(Size = new System.Drawing.Size(150, 65), Location = new Point(12, 17))

let mutable i = 0

for evaluation in evaluations do
    i <- lbxClassifications.Items.Add evaluation

classification.Controls.Add lbxClassifications

[<EntryPoint>]
let main argv =
    Application.Run classification
    0

This would produce:

Accessing a Set

You can use the same technique if the elements are from a class or a record. Other than that, the Set module contains most of the same functions as the List module, allowing you to perform all types of operations.

Characteristics of a Set

 

An Empty Set

An empty set is one that doesn't contain any element. In algebra, an empty set is represented with the uppercase phi letter. The lette can be assigned to an uppercase letter. Here is an example:

A = ∅

In algebra, to visually represent a set, we draw an empty or blank circle:

Set

To create an empty set, declare a variable and assign the empty property of the Set class to it. Here is an example:

let something = Set.empty

To let you find out whether a set is empty, the Set module provides a function named isEmpty. Its signature is:

Set.isEmpty : Set<'T> -> bool

Here is an example of calling this function:

open System
open System.Drawing
open System.Windows.Forms 

let evaluations = set [ "True Positive"; "True Negative"; "False Positive"; "False Negative" ]

let classification = new Form(MaximizeBox = false, StartPosition = FormStartPosition.CenterScreen,
                                    Text = "Classification", ClientSize = new System.Drawing.Size(175, 92)) 

let lbxClassifications = new ListBox(Size = new System.Drawing.Size(150, 65), Location = new Point(12, 17))

let mutable i = 0

if Set.isEmpty evaluations then
    MessageBox.Show("The set doesn't contain any element", "Classification",
                    MessageBoxButtons.OK, MessageBoxIcon.Information) |> ignore
else
    for evaluation in evaluations do
        i <- lbxClassifications.Items.Add evaluation

classification.Controls.Add lbxClassifications

[<EntryPoint>]
let main argv =
    Application.Run classification
    0

As an alternative, the Set class is equipped with a function named IsEmpty. Its signature is:

member this.IsEmpty :  bool

The Number of Elements in a Set

The number of elements in a set is referred to as its length or count. A set is said to be finite if it contains a fixed number of elements. An infinite set is one whose count is not fixed. To let you get the number of elements of a set, the Set module provides a property named count. Here is an example:

open System
open System.Drawing
open System.Windows.Forms

type ZoneInclusion = | Entirely | Split

type State = {
    Name : string
    Inclusion : ZoneInclusion }

let eastern = set [ { Name = "Maine";           Inclusion = Entirely }
                    { Name = "Vermont";         Inclusion = Entirely }
                    { Name = "New Hampshire";   Inclusion = Entirely }
                    { Name = "Massachusetts";   Inclusion = Entirely }
                    { Name = "Rhode Island";    Inclusion = Entirely }
                    { Name = "Connecticut";     Inclusion = Entirely }
                    { Name = "Michigan";        Inclusion = Split    }
                    { Name = "New York";        Inclusion = Entirely }
                    { Name = "New Jersey";      Inclusion = Entirely }
                    { Name = "Indiana";         Inclusion = Split    }
                    { Name = "Ohio";            Inclusion = Entirely }
                    { Name = "Pennsylvania";    Inclusion = Entirely }
                    { Name = "Delaware";        Inclusion = Entirely }
                    { Name = "Maryland";        Inclusion = Entirely }
                    { Name = "Washington D.C."; Inclusion = Entirely }
                    { Name = "West Virginia";   Inclusion = Entirely }
                    { Name = "Kentucky";        Inclusion = Split    }
                    { Name = "Virginia";        Inclusion = Entirely }
                    { Name = "Tennessee";       Inclusion = Split    }
                    { Name = "North Carolina";  Inclusion = Entirely }
                    { Name = "South Carolina";  Inclusion = Entirely }
                    { Name = "Georgia";         Inclusion = Entirely }
                    { Name = "Alabama";         Inclusion = Split    }
                    { Name = "Florida";         Inclusion = Split    } ]

let count = Set.count eastern

let timeManagement = new Form(MaximizeBox = false, Text = "Time Management",
                              ClientSize = new System.Drawing.Size(325, 55),
                              StartPosition = FormStartPosition.CenterScreen)

let lblNumberOfStates = new Label(AutoSize = true, Location = new Point(14, 17),
                                  Anchor = (AnchorStyles.Left ||| AnchorStyles.Bottom))
timeManagement.Controls.Add lblNumberOfStates

lblNumberOfStates.Text <- "Number of US states involved with Eastern Time Zone: " + sprintf "%d" count

[<EntryPoint>]
let main argv = 
    Application.Run timeManagement
    0

This would produce:

The Number of Elements in a Set

As an alternative, the Set class is equipped with a property named Count. Here is an example of accessing it:

let names = set [ "Kevin"; "Jane"; "Daniel"; "James"; "Ruth"; "Paul" ]

sprintf "The set contains %i elements" names.Count

A Set is Automatically Sorted

After a set has been created, every time before it is used, the compiler first internally sorts the elements of the set, based on their type. If the set is made of numbers, they are sorted in incrementing order. Here is an example:

let series = set [ 20; 8; 93; 405; 8; 3; 40 ]

This would produce:

set [3; 8; 20; 40; 93; 405]

If the members of the set are strings, the set gets sorted in alphabetical order. Here is an example we saw earlier:

let names = set [ "Kevin"; "Jane"; "Daniel"; "Ruth"; "Paul" ]

This would produce:

set [ Daniel; Jane; Kevin; Paul; Ruth ]

If the set is made of dates, they are sorted in chronological order. Here is an example:

No Duplicate Value in a Set

A set should (must) not have a duplicate element. If you add duplicate values to a set, the compiler would internally remove every duplicate element. Consider the following example:

open System
open System.Drawing
open System.Windows.Forms 

let names = set [ "Kevin";
		  "Jane";
		  "Daniel";
		  "James";
		  "Ruth";
		  "Jane";
		  "Paul";
		  "James" ]

let employment = new Form(MaximizeBox = false, StartPosition = FormStartPosition.CenterScreen,
                          Text = "Employment", ClientSize = new System.Drawing.Size(175, 115)) 

let lbxEmployees  : ListBox = new ListBox(Size = new System.Drawing.Size(150, 85), Location = new Point(12, 17))

let mutable i = 0

for name in names do
    i <- lbxEmployees.Items.Add name

employment.Controls.Add lbxEmployees

[<EntryPoint>]
let main argv =
    Application.Run employment
    0

Notice that some elements are repeated. This program would produce:

No Duplicate Value in a Set

Notice that the end result doesn't contain duplicates.

The Lowest Value of a Set

As mentioned already, after a set has been created but before it is used, the compiler internally rearranges the elements. As a result, the element that was first added may loose its posibion. To let you find out what element is currently the lowest, the Set class is equipped with a property named MinimumElement. Here is an example of a set:

open System
open System.Drawing
open System.Windows.Forms

type ZoneInclusion = | Entirely | Split

type State = {
    Name : string
    Inclusion : ZoneInclusion }

let eastern = set [ { Name = "Maine";           Inclusion = Entirely }
                    { Name = "Vermont";         Inclusion = Entirely }
                    { Name = "New Hampshire";   Inclusion = Entirely }
                    { Name = "Massachusetts";   Inclusion = Entirely }
                    { Name = "Rhode Island";    Inclusion = Entirely }
                    { Name = "Connecticut";     Inclusion = Entirely }
                    { Name = "Michigan";        Inclusion = Split    }
                    { Name = "New York";        Inclusion = Entirely }
                    { Name = "New Jersey";      Inclusion = Entirely }
                    { Name = "Indiana";         Inclusion = Split    }
                    { Name = "Ohio";            Inclusion = Entirely }
                    { Name = "Pennsylvania";    Inclusion = Entirely }
                    { Name = "Delaware";        Inclusion = Entirely }
                    { Name = "Maryland";        Inclusion = Entirely }
                    { Name = "Washington D.C."; Inclusion = Entirely }
                    { Name = "West Virginia";   Inclusion = Entirely }
                    { Name = "Kentucky";        Inclusion = Split    }
                    { Name = "Virginia";        Inclusion = Entirely }
                    { Name = "Tennessee";       Inclusion = Split    }
                    { Name = "North Carolina";  Inclusion = Entirely }
                    { Name = "South Carolina";  Inclusion = Entirely }
                    { Name = "Georgia";         Inclusion = Entirely }
                    { Name = "Alabama";         Inclusion = Split    }
                    { Name = "Florida";         Inclusion = Split    } ]

let first = eastern.MinimumElement

let timeManagement = new Form(MaximizeBox = false, Text = "Time Management",
                              ClientSize = new System.Drawing.Size(325, 55),
                              StartPosition = FormStartPosition.CenterScreen)

let lblState = new Label(AutoSize = true, Location = new Point(14, 17),
                                  Anchor = (AnchorStyles.Left ||| AnchorStyles.Bottom))
timeManagement.Controls.Add lblState

lblState.Text <- "First state in alphabetical order: " + first.Name

[<EntryPoint>]
let main argv = 
    Application.Run timeManagement
    0

This would produce:

The Lowest Value of a Set

Alternatively, the Set module provides a member variable named minElement. Here is an example of accessing it:

let lunchSpecial = set [ "Sweet and Sour Chicken";
                         "Cashew Chicken";
                         "Kung Pao Chicken";
                         "Szechuan Chicken";
                         "Hunan Chicken"; ]

let first = Set.minElement lunchSpecial

sprintf "The first food item is named %s" first

This would produce:

set [ "Cashew Chicken"
      "Hunan Chicken"
      "Kung Pao Chicken"
      "Sweet and Sour Chicken"
      "Szechuan Chicken" ]

The first food item is named Cashew Chicken

The Highest Element in a Set

To let you get the highest element in a set, the Set class is equipped with a property named MaximumElement. Here is an example of accessing it:

let numbers = set [ 10; 830; 4; 80; 38482; 2; 30; 48 ]

let highest = numbers.MaximumElement

sprintf "The highest number of the set is %i" highest

This would produce:

set [ 2; 4; 10; 30; 48; 80; 830; 38482 ]

The highest number of the set is 38482

As an alternatively, the Set module provides a member named maxElement. Here is an example of using it:

let lunchSpecial = set [ "Sweet and Sour Chicken";
                         "Cashew Chicken";
                         "Kung Pao Chicken";
                         "Szechuan Chicken";
                         "Hunan Chicken"; ]

let last = Set.maxElement lunchSpecial

sprintf "The last food item is named %s" last

This would produce:

set [ "Cashew Chicken"
      "Hunan Chicken"
      "Kung Pao Chicken"
      "Sweet and Sour Chicken"
      "Szechuan Chicken" ]

The last food item is named Szechuan Chicken

Fundamental Operations on a Set

   

A Singleton

A singleton is a set that contains only one element. To let you create a singleton, the Set module provides the singleton function. Its signature is:

Set.singleton : 'T -> Set<'T>

Here is an example:

let nbr = Set.singleton 248

sprintf "Number: %A" nbr

This wold produce:

Number: set [248]

Iterating Through a Set

To let you iterate through the elements of a set, the Set module provides a functions named iter. Its signature is:

Set.iter : ('T -> unit) -> Set<'T> -> unit 

This function takes two arguments. The first is a function to use on each element. The second argument is a list. Here is an example:

open System
open System.Drawing
open System.Windows.Forms

type ZoneInclusion = | Entirely | Split

type State = {
    Name : string
    Inclusion : ZoneInclusion }

let eastern = set [ { Name = "Maine";           Inclusion = Entirely }
                    { Name = "Vermont";         Inclusion = Entirely }
                    { Name = "New Hampshire";   Inclusion = Entirely }
                    { Name = "Massachusetts";   Inclusion = Entirely }
                    { Name = "Rhode Island";    Inclusion = Entirely }
                    { Name = "Connecticut";     Inclusion = Entirely }
                    { Name = "Michigan";        Inclusion = Split    }
                    { Name = "New York";        Inclusion = Entirely }
                    { Name = "New Jersey";      Inclusion = Entirely }
                    { Name = "Indiana";         Inclusion = Split    }
                    { Name = "Ohio";            Inclusion = Entirely }
                    { Name = "Pennsylvania";    Inclusion = Entirely }
                    { Name = "Delaware";        Inclusion = Entirely }
                    { Name = "Maryland";        Inclusion = Entirely }
                    { Name = "Washington D.C."; Inclusion = Entirely }
                    { Name = "West Virginia";   Inclusion = Entirely }
                    { Name = "Kentucky";        Inclusion = Split    }
                    { Name = "Virginia";        Inclusion = Entirely }
                    { Name = "Tennessee";       Inclusion = Split    }
                    { Name = "North Carolina";  Inclusion = Entirely }
                    { Name = "South Carolina";  Inclusion = Entirely }
                    { Name = "Georgia";         Inclusion = Entirely }
                    { Name = "Alabama";         Inclusion = Split    }
                    { Name = "Florida";         Inclusion = Split    } ]

let count = Set.count eastern

let timeManagement = new Form(MaximizeBox = false, Text = "Time Management",
                              ClientSize = new System.Drawing.Size(250, 210),
                              StartPosition = FormStartPosition.CenterScreen)

let lvwTimeZones = new ListView(GridLines = true, View = View.Details,
                                Size = new System.Drawing.Size(225, 144),
                                FullRowSelect = true, Location = new Point(12, 12),
                                Anchor = (AnchorStyles.Left ||| AnchorStyles.Top ||| AnchorStyles.Right ||| AnchorStyles.Bottom))

let mutable col = lvwTimeZones.Columns.Add("State", 140)
col <- lvwTimeZones.Columns.Add("Inclusion", 60)

timeManagement.Controls.Add lvwTimeZones

let lblNumberOfStates = new Label(Size = new System.Drawing.Size(225, 42), Location = new Point(14, 170),
                                  Anchor = (AnchorStyles.Left ||| AnchorStyles.Bottom))
timeManagement.Controls.Add lblNumberOfStates

Set.iter (fun timeZone ->
    let mutable lviTimeZone = new ListViewItem()
    lviTimeZone.Text <- (sprintf "%s" timeZone.Name)
    lviTimeZone.SubItems.Add (sprintf "%A" timeZone.Inclusion) |> ignore
    lvwTimeZones.Items.Add lviTimeZone |> ignore) eastern

lblNumberOfStates.Text <- "Number of states entirely or partially involved with Eastern Time Zone: " + sprintf "%d" count

[<EntryPoint>]
let main argv = 
    Application.Run timeManagement
    0

As an alternative, you can apply the set to the function call. Here is an example:

eastern |> Set.iter (fun timeZone ->
        let mutable lviTimeZone = new ListViewItem()
        lviTimeZone.Text <- (sprintf "%s" timeZone.Name)
        lviTimeZone.SubItems.Add (sprintf "%A" timeZone.Inclusion) |> ignore
        lvwTimeZones.Items.Add lviTimeZone |> ignore)

This would produce:

Iterating Through a Set

Adding an Element to a Set

As you may know already, collections in F# are immutable; meaning that once you create a set, you cannot add new elements to it. Instead, you can create a new set that contains elements from an existing set and other elements. To let you perform this operation, the Set class is equipped with a method named Add. Its signature is:

member this.Add : 'T -> Set<'T>

This method takes one argument as the item to be added to the set that called it. Here are two examples:

open System
open System.Drawing
open System.Windows.Forms

type ChemicalElement = {
        AtomicNumber : int
        Name         : string
        Symbol       : string
        AtomicMass   : string }

let periodicTable = set [ { Name = "Hydrogen"; Symbol = "H";  AtomicNumber =  1; AtomicMass = "1.0079"  }
                          { Name = "Helium";   Symbol = "He"; AtomicNumber =  2; AtomicMass = "4.0026"  }
                          { Name = "Lithium";  Symbol = "Li"; AtomicNumber =  3; AtomicMass = "6.941"   }
                          { Name = "Berylium"; Symbol = "Be"; AtomicNumber =  4; AtomicMass = "9.0122"  }
                          { Name = "Boron";    Symbol = "B";  AtomicNumber =  5; AtomicMass = "10.811"  }
                          { Name = "Carbon";   Symbol = "C";  AtomicNumber =  6; AtomicMass = "12.011"  }
                          { Name = "Nitrogen"; Symbol = "N";  AtomicNumber =  7; AtomicMass = "14.0067" }
                          { Name = "Oxygen";   Symbol = "O";  AtomicNumber =  8; AtomicMass = "15.9994" }
                          { Name = "Fluorine"; Symbol = "F";  AtomicNumber =  9; AtomicMass = "18.9984" }
                          { Name = "Neon";     Symbol = "Ne"; AtomicNumber = 10; AtomicMass = "20.1797" } ]

let withSodium = periodicTable.Add { AtomicNumber =  11; Name = "Sodium"; Symbol = "Na";  AtomicMass = "22.9898" }
let withMagnesium = withSodium.Add { AtomicNumber =  12; Name = "Magnesium"; Symbol = "Mg";  AtomicMass = "24.3050" }

let chemistry = new Form(MaximizeBox = false, Text = "Periodic Table",
                         ClientSize = new System.Drawing.Size(330, 192),
                         StartPosition = FormStartPosition.CenterScreen)

let lvwElements = new ListView(GridLines = true, View = View.Details,
                                 Size = new System.Drawing.Size(303, 166),
                                 FullRowSelect = true, Location = new Point(12, 12))

let mutable col = lvwElements.Columns.Add("Atomic Number", 85)
col <- lvwElements.Columns.Add("Name", 70)
col <- lvwElements.Columns.Add("Symbol", 50, HorizontalAlignment.Center)
col <- lvwElements.Columns.Add("Atomic Mass", 75, HorizontalAlignment.Right)

Set.iter (fun (element : ChemicalElement) -> 
    let mutable lviElement = new ListViewItem()
    lviElement.Text <- (sprintf "%i" element.AtomicNumber)
    lviElement.SubItems.Add (sprintf "%s" element.Name) |> ignore
    lviElement.SubItems.Add (sprintf "%s" element.Symbol) |> ignore
    lviElement.SubItems.Add (sprintf "%s" element.AtomicMass) |> ignore
    lvwElements.Items.Add lviElement |> ignore) withMagnesium

chemistry.Controls.Add lvwElements

[<EntryPoint>]
let main argv = 
    Application.Run chemistry
    0

This would produce:

Accessing a Set - Periodic Table

Because the Set.Add() method returns a set, you can keep calling it to add as many elements as you want. Here is an example that calls it three times to add some elements:

open System
open System.Drawing
open System.Windows.Forms

type ChemicalElement = {
        AtomicNumber : int
        Name         : string
        Symbol       : string
        AtomicMass   : string }

let periodicTable = set [ { Name = "Hydrogen"; Symbol = "H";  AtomicNumber =  1; AtomicMass = "1.0079"  }
                          { Name = "Helium";   Symbol = "He"; AtomicNumber =  2; AtomicMass = "4.0026"  }
                          { Name = "Lithium";  Symbol = "Li"; AtomicNumber =  3; AtomicMass = "6.941"   }
                          { Name = "Berylium"; Symbol = "Be"; AtomicNumber =  4; AtomicMass = "9.0122"  }
                          { Name = "Boron";    Symbol = "B";  AtomicNumber =  5; AtomicMass = "10.811"  }
                          { Name = "Carbon";   Symbol = "C";  AtomicNumber =  6; AtomicMass = "12.011"  }
                          { Name = "Nitrogen"; Symbol = "N";  AtomicNumber =  7; AtomicMass = "14.0067" }
                          { Name = "Oxygen";   Symbol = "O";  AtomicNumber =  8; AtomicMass = "15.9994" }
                          { Name = "Fluorine"; Symbol = "F";  AtomicNumber =  9; AtomicMass = "18.9984" }
                          { Name = "Neon";     Symbol = "Ne"; AtomicNumber = 10; AtomicMass = "20.1797" } ]

let withSodium = periodicTable.Add { AtomicNumber =  11; Name = "Sodium"; Symbol = "Na";  AtomicMass = "22.9898" }
let withMagnesium = withSodium.Add { AtomicNumber =  12; Name = "Magnesium"; Symbol = "Mg";  AtomicMass = "24.3050" }

let elements = (((((withMagnesium.Add { Name = "Aluminium"; AtomicNumber =  13; Symbol = "Al";  AtomicMass = "26.9815" })
               .Add { Name = "Silicon";    AtomicNumber =  14; Symbol = "Si"; AtomicMass = "28.0855" })
               .Add { Name = "Phosphorus"; AtomicNumber =  15; Symbol = "P";  AtomicMass = "30.9738" })
               .Add { Name = "Sulfur";     AtomicNumber =  16; Symbol = "S";  AtomicMass = "32.066"  })
               .Add { Name = "Chlorine";   AtomicNumber =  17; Symbol = "Cl"; AtomicMass = "35.4527" })
                .Add { Name = "Argon";     AtomicNumber =  18; Symbol = "Ar"; AtomicMass = "39.948"  }

let chemistry = new Form(MaximizeBox = false, Text = "Periodic Table",
                         ClientSize = new System.Drawing.Size(330, 192),
                         StartPosition = FormStartPosition.CenterScreen)

let lvwElements = new ListView(GridLines = true, View = View.Details,
                                 Size = new System.Drawing.Size(303, 166),
                                 FullRowSelect = true, Location = new Point(12, 12))

let mutable col = lvwElements.Columns.Add("Atomic Number", 85)
col <- lvwElements.Columns.Add("Name", 70)
col <- lvwElements.Columns.Add("Symbol", 50, HorizontalAlignment.Center)
col <- lvwElements.Columns.Add("Atomic Mass", 75, HorizontalAlignment.Right)

Set.iter (fun (element : ChemicalElement) -> 
    let mutable lviElement = new ListViewItem()
    lviElement.Text <- (sprintf "%i" element.AtomicNumber)
    lviElement.SubItems.Add (sprintf "%s" element.Name) |> ignore
    lviElement.SubItems.Add (sprintf "%s" element.Symbol) |> ignore
    lviElement.SubItems.Add (sprintf "%s" element.AtomicMass) |> ignore
    lvwElements.Items.Add lviElement |> ignore) elements

chemistry.Controls.Add lvwElements

[<EntryPoint>]
let main argv = 
    Application.Run chemistry
    0

This would produce:

Accessing a Set - Periodic Table

To support this operation, the Set module provides a function named add. Its signature is:

Set.add : 'T -> Set<'T> -> Set<'T>

This function takes two arguments. The first is the element to add to the second argument which is a set. The function returns a set. You can call the function once to add an item. In the same way, you can keep calling the Set.add() function to add as many elements as you want.

     
 

A Mutable Set

A mentioned already, when a set is created, it number of elements is fixed, which means that you cannot add new elements to it, except if you want to create a new set. An alternative is to make the set mutable. This would allow you to add items to a set that already holds one or more elements. Here is an example:

open System
open System.Drawing
open System.Windows.Forms

type ChemicalElement = {
        AtomicNumber : int
        Name         : string
        Symbol       : string
        AtomicMass   : string }

let periodicTable = set [ { Name = "Hydrogen"; Symbol = "H";  AtomicNumber =  1; AtomicMass = "1.0079"  }
                          { Name = "Helium";   Symbol = "He"; AtomicNumber =  2; AtomicMass = "4.0026"  }
                          { Name = "Lithium";  Symbol = "Li"; AtomicNumber =  3; AtomicMass = "6.941"   }
                          { Name = "Berylium"; Symbol = "Be"; AtomicNumber =  4; AtomicMass = "9.0122"  }
                          { Name = "Boron";    Symbol = "B";  AtomicNumber =  5; AtomicMass = "10.811"  }
                          { Name = "Carbon";   Symbol = "C";  AtomicNumber =  6; AtomicMass = "12.011"  }
                          { Name = "Nitrogen"; Symbol = "N";  AtomicNumber =  7; AtomicMass = "14.0067" }
                          { Name = "Oxygen";   Symbol = "O";  AtomicNumber =  8; AtomicMass = "15.9994" }
                          { Name = "Fluorine"; Symbol = "F";  AtomicNumber =  9; AtomicMass = "18.9984" }
                          { Name = "Neon";     Symbol = "Ne"; AtomicNumber = 10; AtomicMass = "20.1797" } ]

let withSodium = periodicTable.Add { AtomicNumber =  11; Name = "Sodium"; Symbol = "Na";  AtomicMass = "22.9898" }
let withMagnesium = withSodium.Add { AtomicNumber =  12; Name = "Magnesium"; Symbol = "Mg";  AtomicMass = "24.3050" }

let elements = (((((withMagnesium.Add { Name = "Aluminium"; AtomicNumber =  13; Symbol = "Al";  AtomicMass = "26.9815" })
                       .Add { Name = "Silicon";    AtomicNumber =  14; Symbol = "Si"; AtomicMass = "28.0855" })
                       .Add { Name = "Phosphorus"; AtomicNumber =  15; Symbol = "P";  AtomicMass = "30.9738" })
                       .Add { Name = "Sulfur";     AtomicNumber =  16; Symbol = "S";  AtomicMass = "32.066"  })
                       .Add { Name = "Chlorine";   AtomicNumber =  17; Symbol = "Cl"; AtomicMass = "35.4527" })
                        .Add { Name = "Argon";     AtomicNumber =  18; Symbol = "Ar"; AtomicMass = "39.948"  }

let mutable chemicalTable = elements.Add { AtomicNumber =  19; Name = "Potassium"; Symbol = "K";  AtomicMass = "39.0983" }
chemicalTable <- chemicalTable.Add { AtomicNumber =  19; Name = "Potassium"; Symbol = "K";  AtomicMass = "39.0983" }
chemicalTable <- chemicalTable.Add { AtomicNumber =  20; Name = "Calcium";   Symbol = "Ca"; AtomicMass = "40.078"  }
chemicalTable <- chemicalTable.Add { AtomicNumber =  21; Name = "Scandium";  Symbol = "Sc"; AtomicMass = "44.9559" }
chemicalTable <- chemicalTable.Add { AtomicNumber =  22; Name = "Titanium";  Symbol = "Ti"; AtomicMass = "47.88"   }

let chemistry = new Form(MaximizeBox = false, Text = "Periodic Table",
                         ClientSize = new System.Drawing.Size(330, 192),
                         StartPosition = FormStartPosition.CenterScreen)

let lvwElements = new ListView(GridLines = true, View = View.Details,
                                 Size = new System.Drawing.Size(303, 166),
                                 FullRowSelect = true, Location = new Point(12, 12))

let mutable col = lvwElements.Columns.Add("Atomic Number", 85)
col <- lvwElements.Columns.Add("Name", 70)
col <- lvwElements.Columns.Add("Symbol", 50, HorizontalAlignment.Center)
col <- lvwElements.Columns.Add("Atomic Mass", 75, HorizontalAlignment.Right)

Set.iter (fun (element : ChemicalElement) -> 
    let mutable lviElement = new ListViewItem()
    lviElement.Text <- (sprintf "%i" element.AtomicNumber)
    lviElement.SubItems.Add (sprintf "%s" element.Name) |> ignore
    lviElement.SubItems.Add (sprintf "%s" element.Symbol) |> ignore
    lviElement.SubItems.Add (sprintf "%s" element.AtomicMass) |> ignore
    lvwElements.Items.Add lviElement |> ignore) chemicalTable

chemistry.Controls.Add lvwElements

[<EntryPoint>]
let main argv = 
    Application.Run chemistry
    0

This would produce:

Accessing a Set - Periodic Table    Accessing a Set - Periodic Table

In the same way, you can keep calling the method to remove more elements. In the Set module, an alternative to the Set.Remove() method is a function named remove. Its signature is:

Set.remove : 'T -> Set<'T> -> Set<'T>

A Duplicate Set

In algebra, after creating a set A, you may want to create another set B that contains the same elements as A. To do this, you can simply assign the original set (A) to the new one (B). This would be done as follows:

A = { Kevin Walchild, Jane Overton, Daniel Albertson,
      Ruth Oyawale, Jane Ouelette, Paul Sullivan }

B = A

Now, sets A and B have the same elements:

Set

Here is an example of creating a duplicate set:

open System
open System.Drawing
open System.Windows.Forms

let censusBureauNewEngland = set [ "Maine"; "Vermont"; "New Hampshire"; "Massachusetts"; "Rhode Island"; "Connecticut" ]

let getCount states : int =
    Set.count states

let USRegions = new Form(MaximizeBox = false, Text = "US Regions",
                         ClientSize = new System.Drawing.Size(320, 185),
                         StartPosition = FormStartPosition.CenterScreen)

let lbxRegions = new ListBox(Location = new Point(12, 12),
                             Size = new System.Drawing.Size(295, 100),
                             Anchor = (AnchorStyles.Left ||| AnchorStyles.Top ||| AnchorStyles.Right ||| AnchorStyles.Bottom))
USRegions.Controls.Add lbxRegions

let lblNumberOfStates = new Label(Size = new System.Drawing.Size(295, 28), Location = new Point(14, 115),
                                  Anchor = (AnchorStyles.Left ||| AnchorStyles.Bottom))
USRegions.Controls.Add lblNumberOfStates

let btnDuplicate = new Button(Size = new System.Drawing.Size(295, 30),
                              Location = new Point(12, 145), Text = "Duplicate",
                              Anchor = (AnchorStyles.Left ||| AnchorStyles.Right ||| AnchorStyles.Bottom))
USRegions.Controls.Add btnDuplicate

let display states caption =
    lbxRegions.Items.Clear()

    USRegions.Text <- caption + " - New England"
    states |> Set.iter (fun state -> lbxRegions.Items.Add (sprintf "%s" state) |> ignore)

    let total = getCount states
    lblNumberOfStates.Text <- "Number of states in New England (" + caption + "): " + sprintf "%d" total

let USRegionsLoad e =
    display censusBureauNewEngland "US Census Bureau"
USRegions.Load.Add USRegionsLoad

let btnDuplicateClick e =
    let bureauOfEconomicAnalysisNewEngland = censusBureauNewEngland

    display bureauOfEconomicAnalysisNewEngland "Bureau of Economic Analysis"
btnDuplicate.Click.Add btnDuplicateClick

[<EntryPoint>]
let main argv = 
    Application.Run USRegions
    0

Here is an example of running the program:

Creating a Duplicate Set Creating a Duplicate Set

Once you have created the set, you can manipulate it as you see fit.

A Union of Sets

Imagine you have two sets A and B defined as follows:

A = { Kevin, Jane, Daniel }
B = { Raul, Kevin, Tiffany, Michael, Jane 

Uniting two sets consists of adding them. In F#, you get the elements of each set and add them to create a new set. If there is an element that is found in both sets, only one of the duplicate elements is added to the new set. In algebra, this operation is written as follows:

A ∪ B = { x|x ∈ A or x ∈ B 

This can be visually illustrated as follows:

A Union of Two Sets

To help you unite two sets, the Set class is equipped with the + operator. Its signature is:

static member ( + ) : Set<'T> * Set<'T> -> Set<'T>

The + operator takes a set on each part and it produces their union. Here is an example:

open System
open System.Drawing
open System.Windows.Forms

let censusBureauSouthAtlantic = set [ "Delaware"; "West Virginia"; "Maryland"; "Washington D.C.";
                                      "Virginia"; "North Carolina"; "South Carolina"; "Georgia"; "Florida" ]
let bureauOfEconomicAnalysisSoutheast = set [ "West Virginia"; "Kentucky";
                                              "Virginia"; "Tennessee"; "North Carolina";
                                              "South Carolina"; "Arkansas"; "Louisiana";
                                              "Mississippi"; "Alabama"; "Georgia"; "Florida"; ]

let union = censusBureauSouthAtlantic + bureauOfEconomicAnalysisSoutheast

let USRegions = new Form(MaximizeBox = false, Text = "US Regions",
                         ClientSize = new System.Drawing.Size(390, 285),
                         StartPosition = FormStartPosition.CenterScreen)

USRegions.Controls.Add(new Label(AutoSize = true, Location = new Point(12, 12),
                                 Text = "US Census Bureau - South Atlantic Region"))

let lbxSouthAtlantic = new ListBox(Size = new System.Drawing.Size(365, 55),
                                   Location = new Point(12, 32), MultiColumn = true)
USRegions.Controls.Add lbxSouthAtlantic

USRegions.Controls.Add(new Label(AutoSize = true, Location = new Point(12, 85),
                                 Text = "Bureau of Economic Analysis - Southeast Region"))

let lbxSoutheast = new ListBox(Size = new System.Drawing.Size(365, 65),
                               Location = new Point(12, 108), MultiColumn = true)
USRegions.Controls.Add lbxSoutheast

USRegions.Controls.Add(new Label(AutoSize = true, Location = new Point(12, 175),
                                 Text = "Union of Both Regions"))

let lbxUnion = new ListBox(Size = new System.Drawing.Size(365, 75),
                                  Location = new Point(12, 198), MultiColumn = true)
USRegions.Controls.Add lbxUnion

let display states =
    lbxSouthAtlantic.Items.Clear()
    states |> Set.iter (fun state -> lbxSouthAtlantic.Items.Add (sprintf "%s" state) |> ignore)

    lbxSoutheast.Items.Clear()
    bureauOfEconomicAnalysisSoutheast |> Set.iter (fun state -> lbxSoutheast.Items.Add (sprintf "%s" state) |> ignore)

    lbxUnion.Items.Clear()
    union |> Set.iter (fun state -> lbxUnion.Items.Add (sprintf "%s" state) |> ignore)
let USRegionsLoad e =
    display censusBureauSouthAtlantic
USRegions.Load.Add USRegionsLoad


[<EntryPoint>]
let main argv = 
    Application.Run USRegions
    0

This would produce:

The Union of Two Sets

In the same way, you can add as many sets as you want by using the + operator among them. Here is an example:

let persons  = set [ "Kevin"; "William"; "Jane"; "Daniel"; "Ruth" ]
let people   = set [ "Antoinette"; "Jane"; "Joshua"; "William"; "Paul" ]
let teachers = set [ "Patrick"; "Ted"; "Jeffrey"; "Peter"; "Jeannette" ]
let students = set [ "Frank"; "Jeffrey"; "Jane"; "Robert" ]

let result = persons + people + teachers + students

This would produce:

Antoinette
Daniel
Frank
Jane
Jeannette
Jeffrey
Joshua
Kevin
Patrick
Paul
Peter
Robert
Ruth
Ted
William
The new set contains 15 elements

As an alternative to the + operator, the Set module provides a function named union. Its signature is:

Set.union : Set<'T> -> Set<'T> -> Set<'T>

This function  takes two sets as arguments and it returns their union. Here is an example of calling this function:

let persons = set [ "Kevin"; "William"; "Jane"; "Daniel"; "Ruth"; ]
let people = set [ "Antoinette"; "Jane"; "Joshua"; "William"; "Paul"; ]

let result = Set.union persons people

In the same way, you can add or unite as many sets as you want. Since the List.union() function takes only two arguments, you can pass one of the arguments as its own call of the function. Here is an example:

let persons  = set [ "Kevin"; "William"; "Jane"; "Daniel"; "Ruth" ]
let people   = set [ "Antoinette"; "Jane"; "Joshua"; "William"; "Paul" ]
let students = set [ "Frank"; "Jeffrey"; "Jane"; "Robert" ]

let result = Set.union (Set.union persons people) students

This would produce:

Antoinette
Daniel
Frank
Jane
Jeffrey
Joshua
Kevin
Paul
Robert
Ruth
William
The new set contains 11 elements

Here is an example that unites four sets:

let persons  = set [ "Kevin"; "William"; "Jane"; "Daniel"; "Ruth" ]
let people   = set [ "Antoinette"; "Jane"; "Joshua"; "William"; "Paul" ]
let teachers = set [ "Patrick"; "Ted"; "Jeffrey"; "Peter"; "Jeannette" ]
let students = set [ "Frank"; "Jeffrey"; "Jane"; "Robert" ]

let result = Set.union (Set.union (Set.union persons people) teachers) students

It is important to know that this method performs a comparison on the elements of both sets so that the result would not allow any duplicate item.

The Intersection of Two Sets

The intersection between two sets is the collection of only elements that belong to both sets. That is, the elements that belong to one set but do not belong to the other set are excluded. In algebra, we write it as follows:

A ∩ B = { x|x ∈ A and x ∈ B 

This can be illustrated as follows:

An Intersection of Two Sets

To let you get the intersecting elements of two sets, the Set module provides a function named intersect. Its signature is:

Set.intersect : Set<'T> -> Set<'T> -> Set<'T>

This function takes two sets as arguments. It considers each element from one set and compares it to element from the other set. Any element that is found in both sets is included in the result that is a new set. Here is an example of calling this function:

open System
open System.Drawing
open System.Windows.Forms

let censusBureauSouthAtlantic = set [ "Delaware"; "West Virginia"; "Maryland"; "Washington D.C.";
                                      "Virginia"; "North Carolina"; "South Carolina"; "Georgia"; "Florida" ]
let bureauOfEconomicAnalysisSoutheast = set [ "West Virginia"; "Kentucky";
                                              "Virginia"; "Tennessee"; "North Carolina";
                                              "South Carolina"; "Arkansas"; "Louisiana";
                                              "Mississippi"; "Alabama"; "Georgia"; "Florida"; ]

let intersection = Set.intersect censusBureauSouthAtlantic bureauOfEconomicAnalysisSoutheast

let USRegions = new Form(MaximizeBox = false, Text = "US Regions",
                         ClientSize = new System.Drawing.Size(390, 245),
                         StartPosition = FormStartPosition.CenterScreen)

USRegions.Controls.Add(new Label(AutoSize = true, Location = new Point(12, 12),
                                 Text = "US Census Bureau - South Atlantic Region"))

let lbxSouthAtlantic = new ListBox(Size = new System.Drawing.Size(365, 55),
                                   Location = new Point(12, 32), MultiColumn = true)
USRegions.Controls.Add lbxSouthAtlantic

USRegions.Controls.Add(new Label(AutoSize = true, Location = new Point(12, 85),
                                 Text = "Bureau of Economic Analysis - Southeast Region"))

let lbxSoutheast = new ListBox(Size = new System.Drawing.Size(365, 65),
                               Location = new Point(12, 108), MultiColumn = true)
USRegions.Controls.Add lbxSoutheast

USRegions.Controls.Add(new Label(AutoSize = true, Location = new Point(12, 175),
                                 Text = "Intersection of Both Regions"))

let lbxIntersection = new ListBox(Size = new System.Drawing.Size(365, 35),
                                  Location = new Point(12, 198), MultiColumn = true)
USRegions.Controls.Add lbxIntersection

let display states =
    lbxSouthAtlantic.Items.Clear()
    states |> Set.iter (fun state -> lbxSouthAtlantic.Items.Add (sprintf "%s" state) |> ignore)

    lbxSoutheast.Items.Clear()
    bureauOfEconomicAnalysisSoutheast |> Set.iter (fun state -> lbxSoutheast.Items.Add (sprintf "%s" state) |> ignore)

    lbxIntersection.Items.Clear()
    intersection |> Set.iter (fun state -> lbxIntersection.Items.Add (sprintf "%s" state) |> ignore)
let USRegionsLoad e =
    display censusBureauSouthAtlantic
USRegions.Load.Add USRegionsLoad


[<EntryPoint>]
let main argv = 
    Application.Run USRegions
    0

This would produce:

Getting the Intersection of Two Sets

Subtracting or Removing Elements from a Set

Consider two sets A and B. The difference between a set A from a set B is the list of elements that are found in set A but are not found in set B. In algebra, this is written as follows:

A - B = { x|x ∈ A and x ∉ B 

This can be illustrated as follows:

The Difference of Two Sets

To let you perform this operation, the Set class is equipped with the - operator. Its signature is:

static member ( - ) : Set<'T> * Set<'T> -> Set<'T>

Here is an example:

open System
open System.Drawing
open System.Windows.Forms

type ZoneInclusion = | Entirely | Split

type State = {
    Name : string
    Inclusion : ZoneInclusion }

let eastern = set [ { Name = "Maine";           Inclusion = Entirely }
                    { Name = "Vermont";         Inclusion = Entirely }
                    { Name = "New Hampshire";   Inclusion = Entirely }
                    { Name = "Massachusetts";   Inclusion = Entirely }
                    { Name = "Rhode Island";    Inclusion = Entirely }
                    { Name = "Connecticut";     Inclusion = Entirely }
                    { Name = "Michigan";        Inclusion = Split    }
                    { Name = "New York";        Inclusion = Entirely }
                    { Name = "New Jersey";      Inclusion = Entirely }
                    { Name = "Indiana";         Inclusion = Split    }
                    { Name = "Ohio";            Inclusion = Entirely }
                    { Name = "Pennsylvania";    Inclusion = Entirely }
                    { Name = "Delaware";        Inclusion = Entirely }
                    { Name = "Maryland";        Inclusion = Entirely }
                    { Name = "Washington D.C."; Inclusion = Entirely }
                    { Name = "West Virginia";   Inclusion = Entirely }
                    { Name = "Kentucky";        Inclusion = Split    }
                    { Name = "Virginia";        Inclusion = Entirely }
                    { Name = "Tennessee";       Inclusion = Split    }
                    { Name = "North Carolina";  Inclusion = Entirely }
                    { Name = "South Carolina";  Inclusion = Entirely }
                    { Name = "Georgia";         Inclusion = Entirely }
                    { Name = "Alabama";         Inclusion = Split    }
                    { Name = "Florida";         Inclusion = Split    } ]

let timeManagement = new Form(MaximizeBox = false, Text = "Time Management",
                              ClientSize = new System.Drawing.Size(250, 250),
                              StartPosition = FormStartPosition.CenterScreen)

let lvwTimeZones = new ListView(GridLines = true, View = View.Details,
                                Size = new System.Drawing.Size(225, 144),
                                FullRowSelect = true, Location = new Point(12, 12),
                                Anchor = (AnchorStyles.Left ||| AnchorStyles.Top ||| AnchorStyles.Right ||| AnchorStyles.Bottom))

let mutable col = lvwTimeZones.Columns.Add("State", 140)
col <- lvwTimeZones.Columns.Add("Inclusion", 60)

timeManagement.Controls.Add lvwTimeZones

let lblNumberOfStates = new Label(Size = new System.Drawing.Size(225, 38), Location = new Point(14, 170),
                                  Anchor = (AnchorStyles.Left ||| AnchorStyles.Bottom))
timeManagement.Controls.Add lblNumberOfStates

let btnRemove = new Button(Location = new Point(12, 215), Text = "Remove Non-State",
                           Anchor = (AnchorStyles.Left ||| AnchorStyles.Bottom), Width = 225)
timeManagement.Controls.Add btnRemove

let display zones =
    lvwTimeZones.Items.Clear()

    zones |> Set.iter (fun timeZone ->
            let mutable lviTimeZone = new ListViewItem()
            lviTimeZone.Text <- (sprintf "%s" timeZone.Name)
            lviTimeZone.SubItems.Add (sprintf "%A" timeZone.Inclusion) |> ignore
            lvwTimeZones.Items.Add lviTimeZone |> ignore)

    lblNumberOfStates.Text <- "Number of states entirely or partially involved with Eastern Time Zone: " + sprintf "%d" zones.Count

let timeManagementLoad e =
    display eastern
timeManagement.Load.Add timeManagementLoad

let btnRemoveClick e =
    let states = eastern - set [{ Name = "Washington D.C."; Inclusion = Entirely }]
    display states
btnRemove.Click.Add btnRemoveClick

[<EntryPoint>]
let main argv = 
    Application.Run timeManagement
    0

This would produce:

Removing an Element from a Set Removing an Element from a Set

On the other hand, the Set module provides a function named difference. Its signature is:

Set.difference : Set<'T> -> Set<'T> -> Set<'T>

This function takes two sets as arguments. Here is an example:

let persons = set [ "Kevin"; "William"; "Rebeccah"; "Jane"; "Daniel"; "Ruth" ]
let people = set [ "Antoinette"; "Jane"; "Joshua"; "William"; "Paul" ]

let result = Set.difference persons people

To let create a new set that contains elements from an existing set minus a certain element, the Set class is equipped with a method named Remove. Its signature is:

member this.Remove : 'T -> Set<'T>

This method takes one argument as the element to be removed from the set that called it. The method produces a new set. Here is an example:

let btnRemoveClick e =
    let states = eastern.Remove { Name = "Washington D.C."; Inclusion = Entirely }
    display states

Deriving a Sub-Set from a Set

To create a new set that gets its element from an existing set, you can apply a condition by which the desired elements would be selected. To let you perform this operation, the Set module provides a function named filter. Its signature is:

Set.filter : ('T -> bool) -> Set<'T> -> Set<'T>

Here is an example:

open System
open System.Drawing
open System.Windows.Forms

type ZoneInclusion = | Entirely | Split

type State = {
    Name : string
    Inclusion : ZoneInclusion }

let eastern = set [ { Name = "Maine";           Inclusion = Entirely }
                    { Name = "Vermont";         Inclusion = Entirely }
                    { Name = "New Hampshire";   Inclusion = Entirely }
                    { Name = "Massachusetts";   Inclusion = Entirely }
                    { Name = "Rhode Island";    Inclusion = Entirely }
                    { Name = "Connecticut";     Inclusion = Entirely }
                    { Name = "Michigan";        Inclusion = Split    }
                    { Name = "New York";        Inclusion = Entirely }
                    { Name = "New Jersey";      Inclusion = Entirely }
                    { Name = "Indiana";         Inclusion = Split    }
                    { Name = "Ohio";            Inclusion = Entirely }
                    { Name = "Pennsylvania";    Inclusion = Entirely }
                    { Name = "Delaware";        Inclusion = Entirely }
                    { Name = "Maryland";        Inclusion = Entirely }
                    { Name = "Washington D.C."; Inclusion = Entirely }
                    { Name = "West Virginia";   Inclusion = Entirely }
                    { Name = "Kentucky";        Inclusion = Split    }
                    { Name = "Virginia";        Inclusion = Entirely }
                    { Name = "Tennessee";       Inclusion = Split    }
                    { Name = "North Carolina";  Inclusion = Entirely }
                    { Name = "South Carolina";  Inclusion = Entirely }
                    { Name = "Georgia";         Inclusion = Entirely }
                    { Name = "Alabama";         Inclusion = Split    }
                    { Name = "Florida";         Inclusion = Split    } ]

let statesEntirelyInTimeZone = eastern |> Set.filter (fun (state : State) -> state.Inclusion = Entirely)

let timeManagement = new Form(MaximizeBox = false, Text = "Time Management",
                              ClientSize = new System.Drawing.Size(250, 210),
                              StartPosition = FormStartPosition.CenterScreen)

let lvwTimeZones = new ListView(GridLines = true, View = View.Details,
                                Size = new System.Drawing.Size(225, 144),
                                FullRowSelect = true, Location = new Point(12, 12),
                                Anchor = (AnchorStyles.Left ||| AnchorStyles.Top ||| AnchorStyles.Right ||| AnchorStyles.Bottom))

let mutable col = lvwTimeZones.Columns.Add("State", 140)
col <- lvwTimeZones.Columns.Add("Inclusion", 60)

timeManagement.Controls.Add lvwTimeZones

let lblNumberOfStates = new Label(Size = new System.Drawing.Size(225, 38), Location = new Point(14, 170),
                                  Anchor = (AnchorStyles.Left ||| AnchorStyles.Bottom))
timeManagement.Controls.Add lblNumberOfStates

let display(zones) =
    lvwTimeZones.Items.Clear()

    zones |> Set.iter (fun timeZone ->
            let mutable lviTimeZone = new ListViewItem()
            lviTimeZone.Text <- (sprintf "%s" timeZone.Name)
            lviTimeZone.SubItems.Add (sprintf "%A" timeZone.Inclusion) |> ignore
            lvwTimeZones.Items.Add lviTimeZone |> ignore)

    lblNumberOfStates.Text <- "Number of states entirely in the Eastern Time Zone: " + sprintf "%d" zones.Count

let timeManagementLoad e =
    display statesEntirelyInTimeZone
timeManagement.Load.Add timeManagementLoad

[<EntryPoint>]
let main argv = 
    Application.Run timeManagement
    0

This would produce:

Filtering Elements From a Set

Mapping Some Elements of a Set

To let you perform an operation on each element of a set to get a new set, the Set module provides a function named map. Its signature is:

Set.map : ('T -> 'U) -> Set<'T> -> Set<'U>

Here is an example:

open System
open System.Drawing
open System.Windows.Forms

let xCoordinates = set [ -3; -2; -2; -1; 0; 1; 2; 3 ]

let yCoordinates = Set.map (fun x -> (x, 2 * x + 3)) xCoordinates

let geometry = new Form(MaximizeBox = false, Text = "Geometry",
                              ClientSize = new System.Drawing.Size(250, 180),
                              StartPosition = FormStartPosition.CenterScreen)

geometry.Controls.Add(new Label(Location = new Point(12, 12),
                                Size = new System.Drawing.Size(200, 30),
                                Text = "Equation: y = 2x + 3 Coordinates"))

let lvwCoordinates = new ListView(GridLines = true, View = View.Details,
                                Size = new System.Drawing.Size(225, 124),
                                FullRowSelect = true, Location = new Point(12, 42))

let mutable col = lvwCoordinates.Columns.Add("X", 40)
col <- lvwCoordinates.Columns.Add("Y", 40)

geometry.Controls.Add lvwCoordinates

let display() =
    lvwCoordinates.Items.Clear()

    for point in yCoordinates do
        let (a, b) = point
        
        let lviCoordinate = new ListViewItem(sprintf "%i" a)
        lviCoordinate.SubItems.Add(sprintf "%i" b) |> ignore
        lvwCoordinates.Items.Add lviCoordinate

let geometryLoad e =
    display()
geometry.Load.Add geometryLoad(**)

[<EntryPoint>]
let main argv = 
    Application.Run geometry
    0

This would produce:

Mapping Some Elements of a Set

Partitioning a Set

To let you segment a set into two, the Set module provides a function named partition. Its signature is:

Set.partition : ('T -> bool) -> Set<'T> -> Set<'T> * Set<'T>

This function takes a function and a list as arguments. The function argument applies a condition to all members of the list. The function returns two lists. You can get the return value as two values or as a pair. Here is an example:

open System
open System.Drawing
open System.Windows.Forms

type ZoneInclusion = | Entirely | Split

type State = {
    Name : string
    Inclusion : ZoneInclusion }

let eastern = set [ { Name = "Maine";           Inclusion = Entirely }
                    { Name = "Vermont";         Inclusion = Entirely }
                    { Name = "New Hampshire";   Inclusion = Entirely }
                    { Name = "Massachusetts";   Inclusion = Entirely }
                    { Name = "Rhode Island";    Inclusion = Entirely }
                    { Name = "Connecticut";     Inclusion = Entirely }
                    { Name = "Michigan";        Inclusion = Split    }
                    { Name = "New York";        Inclusion = Entirely }
                    { Name = "New Jersey";      Inclusion = Entirely }
                    { Name = "Indiana";         Inclusion = Split    }
                    { Name = "Ohio";            Inclusion = Entirely }
                    { Name = "Pennsylvania";    Inclusion = Entirely }
                    { Name = "Delaware";        Inclusion = Entirely }
                    { Name = "Maryland";        Inclusion = Entirely }
                    { Name = "Washington D.C."; Inclusion = Entirely }
                    { Name = "West Virginia";   Inclusion = Entirely }
                    { Name = "Kentucky";        Inclusion = Split    }
                    { Name = "Virginia";        Inclusion = Entirely }
                    { Name = "Tennessee";       Inclusion = Split    }
                    { Name = "North Carolina";  Inclusion = Entirely }
                    { Name = "South Carolina";  Inclusion = Entirely }
                    { Name = "Georgia";         Inclusion = Entirely }
                    { Name = "Alabama";         Inclusion = Split    }
                    { Name = "Florida";         Inclusion = Split    } ]

let entirety, others = eastern |> Set.partition (fun (state : State) -> state.Inclusion = Entirely)

let timeManagement = new Form(MaximizeBox = false, Text = "Time Management",
                              ClientSize = new System.Drawing.Size(250, 425),
                              StartPosition = FormStartPosition.CenterScreen)

let lvwEntirely = new ListView(GridLines = true, View = View.Details,
                                Size = new System.Drawing.Size(225, 280),
                                FullRowSelect = true, Location = new Point(12, 12),
                                Anchor = (AnchorStyles.Left ||| AnchorStyles.Top ||| AnchorStyles.Right))
let mutable col = lvwEntirely.Columns.Add("State", 140)
col <- lvwEntirely.Columns.Add("Inclusion", 60)
timeManagement.Controls.Add lvwEntirely

let lvwOthers = new ListView(GridLines = true, View = View.Details,
                             Size = new System.Drawing.Size(225, 110),
                             FullRowSelect = true, Location = new Point(12, 305),
                             Anchor = (AnchorStyles.Left ||| AnchorStyles.Top ||| AnchorStyles.Right ||| AnchorStyles.Bottom))
col <- lvwOthers.Columns.Add("State", 140)
col <- lvwOthers.Columns.Add("Inclusion", 60)
timeManagement.Controls.Add lvwOthers

let display() =
    lvwEntirely.Items.Clear()
    lvwOthers.Items.Clear()

    entirety |> Set.iter (fun timeZone ->
                let mutable lviTimeZone = new ListViewItem()
                lviTimeZone.Text <- (sprintf "%s" timeZone.Name)
                lviTimeZone.SubItems.Add (sprintf "%A" timeZone.Inclusion) |> ignore
                lvwEntirely.Items.Add lviTimeZone |> ignore)

    others |> Set.iter (fun timeZone ->
                let mutable lviTimeZone = new ListViewItem()
                lviTimeZone.Text <- (sprintf "%s" timeZone.Name)
                lviTimeZone.SubItems.Add (sprintf "%A" timeZone.Inclusion) |> ignore
                lvwOthers.Items.Add lviTimeZone |> ignore)

let timeManagementLoad e =
    display()
timeManagement.Load.Add timeManagementLoad

[<EntryPoint>]
let main argv = 
    Application.Run timeManagement
    0

This would produce:

Partitioning a Set

Boolean Operations on Sets

 

Checking Whether an Element Exists

To let you check whether an element exists in a set, the Set module contains a function named exists. Its signature is:

Set.exists : ('T -> bool) -> Set<'T> -> bool

Here is an example of calling this method:

let foodMenu = set [ "Sweet and Sour Chicken"
                     "Scallion Beef"
                     "Cashew Chicken"
                     "Wonton Soup"
                     "Kung Pao Chicken"
                     "Egg Roll"
                     "Szechuan Chicken"
                     "Shrimp Lobster Sauce"
                     "Hunan Chicken" ]

let restaurantHasWontonSoup = Set.exists (fun item -> item = "Wonton Soup") foodMenu

This would produce:

Does the restaurant serve Wonton Soup? Yes

Checking a Condition for all Elements of a Set

To let you find out whether all elements of a set respond to a certain condition, the Set module provides a function named forall. Its signature is:

Set.forall : ('T -> bool) -> Set<'T> -> bool

Here are examples of calling this function:

let foodMenu = set [ "LS01: Sweet and Sour Chicken"
                     "CS01: Scallion Beef"
                     "LS02: Cashew Chicken"
                     "SP01: Wonton Soup"
                     "LS03: Kung Pao Chicken"
                     "AP01: Egg Roll"
                     "LS04: Szechuan Chicken"
                     "SP02: Shrimp Lobster Sauce"
                     "CS02: Hunan Chicken" ]

let lunchSpecial = set [ "LS01: Sweet and Sour Chicken"
                         "LS02: Cashew Chicken"
                         "LS03: Kung Pao Chicken"
                         "LS04: Szechuan Chicken" ]

let menu1IsForLunchSpecial = Set.forall (fun (item : string) -> item.StartsWith "LS") foodMenu
let menu2IsForLunchSpecial = Set.forall (fun (item : string) -> item.StartsWith "LS") lunchSpecial

match menu1IsForLunchSpecial with
| true -> sprintf "Yes, this menu is for lunch special only"
| false -> sprintf "No, this the restaurant's whole menu"

match menu2IsForLunchSpecial with
| true -> sprintf "Yes, this menu is for lunch special only"
| false -> sprintf "No, this the restaurant's whole menu"

Comparing Sets For Equality

Imagine you have two sets A and B defined as follows:

A = { Kevin Walchild, Jane Overton, Daniel Albertson, Jane Ouelette }
B = { Daniel Albertson, Kevin Walchild, Jane Ouelette, Jane Overton 

Notice that both sets have the same elements. When two sets have exact same elements, we say that those sets are equal. This can be expressed as:

A = B

This operation is commutative, which means the above operation can also be written as:

B = A

To compare two sets for equality, simply use the = operator. Here is an example:

let names = set [ "Kevin"; "Jane"; "Daniel"; "James"; "Ruth"; "Paul"; ]
let students = set [ "Kevin"; "Jane"; "William"; "Daniel"; "James"; "Ruth"; "Paul"; ]

if Set.isEmpty names then
    sprintf "The set is empty"
else
    let duplicate = names = students
    if duplicate then
        sprintf "Both sets are the same"
    else
        sprintf "The sets are different"

Checking Whether a Set Contains a Certain Element

In algebra, to show that a certain element "a" exists in a set A, we would write:

a ∈ A

This is read as "a is an element of set A" or "a is included in set A" or "Set A contains a". To support this operation, the Set class is equippede with a method named Contains. Its signature is:

member this.Contains : 'T -> bool

This function is called on a Set variable. Here is an example:

let names = set [ "Kevin"; "Jane"; "Daniel"; "James"; "Ruth"; "Paul" ]

if Set.isEmpty names then
    sprintf "The set is empty"
else
    let name = names.Contains "Daniel"
    if name then
        sprintf "Daniel is in the set"
    else
        sprintf "Daniel is not in the set"

As an alternative, the Set module provides a function named contains. Its signature is:

Set.contains : 'T -> Set<'T> -> bool

Here is an example:

let lunchSpecial = set [ "Sweet and Sour Chicken"
                         "Cashew Chicken"
                         "Kung Pao Chicken"
                         "Szechuan Chicken"
                         "Hunan Chicken" ]

let verify = Set.contains  "Cashew Chicken" lunchSpecial

In algebra, to state that an element a is not in the set A, we write:

a ∉ A

This reads as "a is not an element of set A" or "a is not included in set A" or "Set A does not contain a". To perform this checking in programming, you can use the NOT Boolean operator "!".

A Subset of Another Set

A set A is a sub-set of another set B if all elements of Set A can be found in Set B. This is expressed in algebra as:

A ⊂ B

This is the same as:

 { Kevin, Jane, Daniel } ⊂ { Raul, Kevin, Tiffany, Daniel, Michael, Jane, Paul 

This can be illustrated as follows:

A Sub-Set of an Existing Set

In algebra, any set is a subset of itself. Also, since the empty set doesn't have any element, the empty set is a subset of any set. We write it as:

∅ ⊂ A

and

∅ ⊂ B

An empty set is also a subset of itself.

To let you find out whether one set is a subset of another, the Set class is equipped with a method named IsSubsetOf. Its signature is:

member this.IsSubsetOf : Set<'T> -> bool

This method is applied to a set variable that calls it. The method takes one argument as the set to check. If all elements if the argument are found in the set variable that called this method, the method returns true. If at least one member of the argument is not found in the set variable, the method returns false. Here is an example of calling this method:

let persons = set [ "Kevin"; "William"; "Rebeccah"; "Jane"; "Daniel"; "Ruth" ]
let students = set [ "Jane"; "William" ]

let result = students.IsSubsetOf persons

sprintf "Set Student is a subset of set Persons: %A " result

As an alternative, the Set module provides a function named isSubset. Its signature is:

Set.isSubset : Set<'T> -> Set<'T> -> bool

This function takes two arguments as the sets to be compared. If all elements of the first argument are found in the second argument, the function returns true. If not, it returns false. Here is an example:

let persons = set [ "Kevin"; "William"; "Rebeccah"; "Jane"; "Daniel"; "Ruth" ]
let students = set [ "Jane"; "William" ]

let result = Set.isSubset students persons

It is important to know that the subset relationship is one way; in other words, the comparison is not commutative: the fact that a set A is a subset of a set B is not vice-versa.

A Proper Subset of Another Set

A set is a subset of itself. Also, when two sets have the exact same members, each set is a subset of the other:

Set

On the other hand, if you have a set A that is strictly a subset of another set B, this means there is at least one element in set B that is not a member of set A. In this case, we say that set A is a property subset of set B. This can be illustrated as follows:

Set

To let you find out if a set is a proper subset of another set, the Set class is equipped with a method named IsProperSubsetOf. Its signature is:

member this.IsProperSubsetOf : Set<'T> -> bool

This method takes a Set value as arguments and performs a comparison on their elements:

  • If both sets are the same, the method returns false. Here is an example:
    let persons = set [ "Kevin"; "William"; "Rebeccah"; "Jane"; "Daniel"; "Ruth" ]
    let students = set [ "Kevin"; "William"; "Rebeccah"; "Jane"; "Daniel"; "Ruth" ]
    
    let result = students.IsProperSubsetOf persons
    If the argument has at least one element that is not in the variable that called it, the method returns false. Here is an example:
    let persons = set [ "Kevin"; "William"; "Rebeccah"; "Jane"; "Daniel"; "Ruth" ]
    let students = set [ "Antoinette"; "Jane"; "William" ]
    
    let result = students.IsProperSubsetOf persons
    If all elements of the argument's set are members of the variable that called it, the method returns true. Here is an example:
    let persons = set [ "Kevin"; "William"; "Rebeccah"; "Jane"; "Daniel"; "Ruth" ]
    let students = set [ "Jane"; "William" ]
    
    let result = students.IsProperSubsetOf persons

As an alternative to the Set.IsProperSubsetOf() method, the Set module provides a function named isProperSubset. Its signature is:

Set.isProperSubset : Set<'T> -> Set<'T> -> bool

This function takes two arguments as the sets to compare but it works the same way as the Set.IsProperSubsetOf() method.

A Super-Set of an Existing Set

Remember that a sub-set is a set whose all elements are also found in another set. A super-set is the reverse of a sub-set. That is, in a superset, all the elements of a set B are found in a set A but set A may have elements that are not found in set B. In algebra, this can be written as follows:

B ⊃ A

To help you make this comparison, the Set class is equipped with a method named IsSupersetOf. Its syntax is:

member this.IsSupersetOf : Set<'T> -> bool

This method takes a Set collection as argument and compares its elements to those of the variable that called it. If all the elements of the argument are found in the variable that called it, the method returns true. Here is an example:

let persons = set [ "Kevin"; "William"; "Rebeccah"; "Jane"; "Daniel"; "Ruth" ]
let students = set [ "Jane"; "William" ]

let result = persons.IsSupersetOf students

This would produce:

Set Persons is a super set of set Student: true

As an alternative to the Set.IsSupersetOf() method, the Set module provides a function named isSuperset. Its signature is:

Set.isProperSubset : Set<'T> -> Set<'T> -> bool

This function takes two arguments as the sets to compare but it works the same way as the Set.IsSupersetOf() method.

A Proper Super-Set of an Existing Set

When it comes to a super-set, if two sets are the same, each one is considered a super-set of the other and the IsSupersetOf() method returns true. By contrast, if a set B is a super-set of A but both sets are not the same, that is, set B has more elements than set A, set B is said to be a property super-set of A. To let you make the comparison to determine this, the Set class is equipped with a method named IsProperSupersetOf. Its syntax is:

member this.IsProperSupersetOf : Set<'T> -> bool

This method works as follows:

  • If both sets are the same, the method returns false. Here is an example:
    let persons = set [ "Kevin"; "William"; "Rebeccah"; "Jane"; "Daniel"; "Ruth" ]
    let students = set [ "Kevin"; "William"; "Rebeccah"; "Jane"; "Daniel"; "Ruth" ]
    
    let result = persons.IsProperSupersetOf students
    This would produce:
    Set Persons is a proper super set of set Students: false
  • If the argument has at least one element that is not in the variable that called it, the method returns false. Here is an example:
    let persons = set [ "Kevin"; "William"; "Rebeccah"; "Jane"; "Daniel"; "Ruth" ]
    let students = set [ "Antoinette"; "Jane"; "William" ]
    
    let result = persons.IsProperSupersetOf students
    This would produce:
    Set Persons is a proper super set of set Students: false
  • If all elements of the argument's set are members of the variable that called it, the method returns true. Here is an example:
    let persons = set [ "Kevin"; "William"; "Rebeccah"; "Jane"; "Daniel"; "Ruth" ]
    let students = set [ "Jane"; "William" ]
    
    let result = persons.IsProperSupersetOf students
    This would produce:
    Set Persons is a proper super set of set Students: true

To let you perform this same operation, the Set module provides a function named isProperSuperset. Its signature is:

Set.isProperSuperset : Set<'T> -> Set<'T> -> bool

Sets and Other Collection Types

 

Introduction

You can create a set from any of the other F# collections. To support the other collections, the Set module provides an appropriate function. After creating the set from the other collection, all of the methods of the Set class and those from the Set module are available.

Creating a Set from a List

To let you create a set from a list, the Set module provides a function named ofList. Its signature is:

Set.ofList : 'T list -> Set<'T>

Here is an example:

let lstNumbers = [ 2 .. 2 .. 20 ]
let lstSomeEquares = [ 4; 16 ]

let setNumbers = Set.ofList lstNumbers
let setSomeEquares = Set.ofList lstSomeEquares
let sub = setSomeEquares.IsSubsetOf setNumbers

Creating a Set from an Array

To let you create a set from an existing array, the Set module provides a function named ofArray. Its signature is:

Set.ofArray : 'T array -> Set<'T>

Here is an example:

let arNames  : string array = [| "James"; "April"; "Annette"; "Hughs"; "June"; "Daniel"; "Martine" |]
let arMonths : string array = [| "January"; "February"; "Mars"; "April"; "May"; "June"; "July" |]

let setNames  = Set.ofArray arNames
let setMonths = Set.ofArray arMonths
   
   
 

Home Copyright © 2015 FunctionX Home