Home

Introduction

 

Fundamentals

 

Introduction

 

 

     
 
 

 

   
   
 

Home Copyright © 2015 FunctionX Home

Home

F# Collections: Maps

   

Introduction to Map Collections

 

Description

A map collection is a type of list where each item is considered in the form Key=Value. In other words, each item is made of two parts:

The items of a map are ordered based on the key. If the keys are based on a primitive type (int, char, string, etc), the compiler automatically sorts them because the structures or classes of those types are already equipped to do so. If you decide to use your own structure or class for the key, you must add the necessary (and required) mechanism. In fact, some of the operations on a map require that the objects be ready to perform comparison. The comparison is made possible by implementing the IComparable interface. Here is an example of how it can be done:

open System

type Major(name, degree) =
    class
        member this.Name   = name
        member this.Degree = degree

        interface IComparable with
            member this.CompareTo(obj : Object) =
                match obj with
                | :? Major as maj -> compare this.Name maj.Name
                | _ -> 0

        override this.GetHashCode() = this.GetHashCode()
        override this.Equals(obj) =
                match obj with
                | :? Major as maj -> this.Name = maj.Name
                | _ -> false
    end

Creating a Map Collection

Both the F# language and the .NET Framework support mapped collections. In its Microsoft.FSharp.Collections namespace, the F# language has a class and a module noth named Map. There is no strict formula to create a map. In other words, you have various options. The list, the array, and the sequence all support maps. To let you create a map from those collections, the Map class is equipped with appropriate methods.

You can use the formula of creating a list of tuples. In this case, you would start with the Map word that precedes [(Key, Value)]. Here is an example:

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

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

To create a map from an existing list, you can call a method named ofList from the Map class. Its signature is:

Map.ofList : 'Key * 'T list -> Map<'Key,'T>

This is equivalent to using it on the above formula. Here is an example:

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

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

An alternative is use the formula of creating an array of tuples as a map. In this case, each item must end with a semi-colon (except for the last where the semi-colon is optional). Here is an example:

let houses = Map [| ("Single Family",  "A single family is a house that stands by itself and is occupied by one or more people who live as family members or acquaintances.");
                    ("Townhouse", "A townhouse is a house that is attached to at least one other house. In most cases, townhouse has 1, 2, or 3 levels (not more, based on the construction). In some cases, a townhouse may be built under or above another townhouse.");
                    ("Condominium", "A comdominium (also called a condo) primarily follows the description of an aprtment. The small difference is that, in most cases, only one company manages all the apartments in the building. In the case of a condo, different independent companies may be in charge of different units. Some other condos in the same building be occupied by people who are currently purchasing, as opposed to renting, them."); |]

To create a map from an existing array, you can call the Map.ofArray() method. Its signature is:

Map.ofArray : ('Key * 'T) [] -> Map<'Key,'T>

This can be used by calling this method on the above technique. Here is an example:

let houses = Map.ofArray [| ("Single Family",  "A single family is a house that stands by itself and is occupied by one or more people who live as family members or acquaintances.")
                            ("Townhouse", "A townhouse is a house that is attached to at least one other house. In most cases, townhouse has 1, 2, or 3 levels (not more, based on the construction). In some cases, a townhouse may be built under or above another townhouse.")
                            ("Condominium", "A comdominium (also called a condo) primarily follows the description of an aprtment. The small difference is that, in most cases, only one company manages all the apartments in the building. In the case of a condo, different independent companies may be in charge of different units. Some other condos in the same building be occupied by people who are currently purchasing, as opposed to renting, them.") |]

To create a map from a known sequence, call the Map.ofSeq() method. Its signature is:

Map.ofSeq : ('Key * 'T) [] -> Map<'Key,'T>

Accessing the Elements of a Map

 

Iterating Through a Map

To access the elements of a map, you have various options. The Map class is equipped with a method named iter that can be used to iterate through the collection. The signature of this method is:

Map.iter : ('Key -> 'T -> unit) -> Map<'Key,'T> -> unit

Here is an example of calling it:

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

type PhysicalCharacteristic =
| Metal
| Metalloid
| NonMetal
| Unknown

type ChemicalElement = {
    Name         : string
    Symbol       : string
    AtomicMass   : string
    Category     : PhysicalCharacteristic  }

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

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

let lvwElements = new ListView(GridLines = true, View = View.Details,
                               Size = new System.Drawing.Size(358, 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)
col <- lvwElements.Columns.Add("Category", 70)

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

chemistry.Controls.Add lvwElements

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

This would produce:

Accessing a Set - Periodic Table

Remember that you can also apply the map to the function call. Here is an example:

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

Accessing Each Element by its Key and Value(s)

In our introduction, we mentioned that each element of a map is made of two parts: a key and a value. To let you access them, the Map class is equipped with an indexed property

Characteristics of a Map

 

An Empty Map

A map is said to be empty if it contains no binding(s). To let you find out whether a map is empty or not, the Map class is equipped with a property named IsEmpty:

member this.IsEmpty :  bool

Here is an example of accessing this property:

match periodicTable.IsEmpty with
| false ->
    periodicTable |> Map.iter (fun number (element : ChemicalElement) ->
        let mutable lviElement = new ListViewItem()
        lviElement.Text <- (sprintf "%i" number)
        lviElement.SubItems.Add (sprintf "%s" element.Name) |> ignore
        lviElement.SubItems.Add (sprintf "%s" element.Symbol) |> ignore
        lviElement.SubItems.Add (sprintf "%s" element.AtomicMass) |> ignore
        lviElement.SubItems.Add (sprintf "%A" element.Category) |> ignore
        lvwElements.Items.Add lviElement |> ignore)
| true -> ()

As an alternative, the Map module provides a function named isEmpty. Its signature is:

Map.isEmpty : Map<'Key,'T> -> bool

Here is an example of calling this function:

match Map.isEmpty periodicTable with
| false ->
    Map.iter (fun number (element : ChemicalElement) ->
        let mutable lviElement = new ListViewItem()
        lviElement.Text <- (sprintf "%i" number)
        lviElement.SubItems.Add (sprintf "%s" element.Name) |> ignore
        lviElement.SubItems.Add (sprintf "%s" element.Symbol) |> ignore
        lviElement.SubItems.Add (sprintf "%s" element.AtomicMass) |> ignore
        lviElement.SubItems.Add (sprintf "%A" element.Category) |> ignore
        lvwElements.Items.Add lviElement |> ignore) periodicTable
| true -> ()

The Number of Elements in a Map

The number of items in a map is represented by a property named Count in the Map class:

member this.Count :  int

Here is an example:

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

let zones = Map.ofArray [| ("UTC-08:00", "Pacific Standard Time (PST)")
                           ("UTC-07:00", "Mountain Standard Time (MST)")
                           ("UTC-06:00", "Central Standard Time (CST)")
                           ("UTC-05:00", "Eastern Standard Time (EST)")
                           ("UTC-04:00", "Atlantic Standard Time (AST)")
                           ("UTC-09:00", "Alaskan Standard Time (AKST)")
                           ("UTC-10:00", "Hawaii-Aleutian Standard Time (HST)")
                           ("UTC-11:00", "Samoa standard time (UTC-11)")
                           ("UTC+10:00", "Chamorro Standard Time (UTC+10)") |]

let USTimeZones = new Form(MaximizeBox = false,
                           Text = "United States Time Zones",
                           ClientSize = new System.Drawing.Size(225, 52),
			   StartPosition = FormStartPosition.CenterScreen) 

let lblNumberOfZones = new Label(AutoSize = true, Location = new Point(22, 17))
USTimeZones.Controls.Add lblNumberOfZones

lblNumberOfZones.Text <- sprintf "The United States uses %i time zones" zones.Count

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

This would produce:

The Number of Elements in a Map

The Indexed Property of a Map

To be able to access or recognize each element of a map, the Map class is equipped with an indexed property named Item. This property gives access to the key and the value of an element:

member this.Item ('Key) : 'Value

Based on this property, a Map variable gives you access to a property named Key and another property named Value. To access these properties, you can use a for loop. These properties work as follows:

Finding An Element in a Map

 

Introduction

ITo help you find an element in a map, the Map module provides a function named find. Its signature is:

Map.find : 'Key -> Map<'Key,'T> -> 'T

This function takes two arguments. The first argument is the key to look for in the second argument, which is the map. Here is an example of calling this function:

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

let houses = Map [| ("Single Family",  "A single family is a house that stands by itself and is occupied by one or more people who live as family members or acquaintances.");
                    ("Townhouse", "A townhouse is a house that is attached to at least one other house. In most cases, townhouse has 1, 2, or 3 levels (not more, based on the construction). In some cases, a townhouse may be built under or above another townhouse.");
                    ("Condominium", "A comdominium (also called a condo) primarily follows the description of an aprtment. The small difference is that, in most cases, only one company manages all the apartments in the building. In the case of a condo, different independent companies may be in charge of different units. Some other condos in the same building be occupied by people who are currently purchasing, as opposed to renting, them."); |]

let realEstate = new Form(MaximizeBox = false, Text = "Real Estate",
                          ClientSize = new System.Drawing.Size(403, 122),
                          StartPosition = FormStartPosition.CenterScreen)

let lbxRealEstate = new ListBox(Location = new Point(12, 12))
realEstate.Controls.Add lbxRealEstate
let txtDescription = new TextBox(Location = new Point(140, 12), Multiline  = true,
                                 Size = new System.Drawing.Size(250, 94), ScrollBars = ScrollBars.Vertical)
realEstate.Controls.Add txtDescription

houses |> Map.iter (fun house description -> lbxRealEstate.Items.Add (sprintf "%s" house) |> ignore)

let lbxRealEstateSelectedIndexChanged e =
    let strHouse = string lbxRealEstate.SelectedItem

    let prop = Map.find strHouse houses
    txtDescription.Text <- prop
lbxRealEstate.SelectedIndexChanged.Add lbxRealEstateSelectedIndexChanged

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

This would produce:

Finding An Element in a Set

Finding An Element in a Set

Finding An Element in a Set

Finding An Element in a Set

To offer an alternative, the Map class is equipped with a method named TryFind. Its signature is:

member this.TryFind : 'Key -> 'Value option

Here is an example:

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

let houses = Map [| ("Single Family",  "A single family is a house that stands by itself and is occupied by one or more people who live as family members or acquaintances.");
                    ("Townhouse", "A townhouse is a house that is attached to at least one other house. In most cases, townhouse has 1, 2, or 3 levels (not more, based on the construction). In some cases, a townhouse may be built under or above another townhouse.");
                    ("Condominium", "A comdominium (also called a condo) primarily follows the description of an aprtment. The small difference is that, in most cases, only one company manages all the apartments in the building. In the case of a condo, different independent companies may be in charge of different units. Some other condos in the same building be occupied by people who are currently purchasing, as opposed to renting, them."); |]

let realEstate = new Form(MaximizeBox = false, Text = "Real Estate",
                          ClientSize = new System.Drawing.Size(403, 122),
                          StartPosition = FormStartPosition.CenterScreen)

let lbxRealEstate = new ListBox(Location = new Point(12, 12))
realEstate.Controls.Add lbxRealEstate
let txtDescription = new TextBox(Location = new Point(140, 12), Multiline  = true,
                                 Size = new System.Drawing.Size(250, 94), ScrollBars = ScrollBars.Vertical)
realEstate.Controls.Add txtDescription

houses |> Map.iter (fun house description -> lbxRealEstate.Items.Add (sprintf "%s" house) |> ignore)

let lbxRealEstateSelectedIndexChanged e =
    let strHouse = string lbxRealEstate.SelectedItem

    let prop = houses.TryFind strHouse 
    txtDescription.Text <- prop.Value
lbxRealEstate.SelectedIndexChanged.Add lbxRealEstateSelectedIndexChanged

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

An alternative, the Map module provides a function named findKey. Its signature is:

Map.findKey : ('Key -> 'T -> bool) -> Map<'Key,'T> -> 'Key

Here an example:

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

type Major(name, degree) =
    class
        member this.Name   = name
        member this.Degree = degree

        interface IComparable with
            member this.CompareTo(obj : Object) =
                match obj with
                | :? Major as maj -> compare this.Name maj.Name
                | _ -> 0

        override this.GetHashCode() = this.GetHashCode()
        override this.Equals(obj) =
                match obj with
                | :? Major as maj -> this.Name = maj.Name
                | _ -> false
    end

let collegeMajors = Map [ (new Major("Linguistics", "B.A."), "Scientific studies of human languages")
                          (new Major("Biology", "B.S."), "Study and understanding of functions and diversity of living organims")
                          (new Major("Chemistry", "B.S."), "Study of matter and changes in matter")
                          (new Major("Earth Science", "B.A."), "Basic chemical processes operating in and on the planet")
                          (new Major("Mechanical Engineering and Applied Mechanics", "B.S."), "Components manufacturing, machines and energy conversion")
                          (new Major("Economics", "B.A."), "Studies of the allocation of scarce resources")
                          (new Major("Computer Engineering", "B.S."), "Design and engineering of computer systems")
                          (new Major("Computer Science", "B.S."), "Computer principles, software systems design, and application development")
                          (new Major("Electrical Engineering", "B.S."), "Study and development of technonogies to create devices using electricity")
                          (new Major("Political Science", "B.A."), "Development of systematic approaches to the understanding of politics")
                          (new Major("Philosophy", "B.A."), "Fundamental aspects of, relations to, and knowledge of, the world")
                          (new Major("Psychology", "B.A."), "Combination of social and natural sciences approaches to the mind and behavior of organisms") ]

let university = new Form(MaximizeBox = false, Text = "State University",
                         ClientSize = new System.Drawing.Size(325, 270),
                         StartPosition = FormStartPosition.CenterScreen)

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

let mutable col = lvwMajors.Columns.Add("Major", 240)
col <- lvwMajors.Columns.Add("Degree", 50, HorizontalAlignment.Center)

university.Controls.Add lvwMajors

let txtDescription = new TextBox(Size = new System.Drawing.Size(300, 36),
                                 Multiline = true, Location = new Point(12, 220),
                                 Anchor = (AnchorStyles.Left ||| AnchorStyles.Right ||| AnchorStyles.Bottom))
university.Controls.Add txtDescription

collegeMajors |> Map.iter (fun major description ->
    let lviMajor = new ListViewItem(sprintf "%s"  major .Name)
    lviMajor.SubItems.Add(sprintf "%s" major.Degree) |> ignore
    lvwMajors.Items.Add lviMajor |> ignore)

let lvwMajorsSelectedIndexChanged(e : ListViewItemSelectionChangedEventArgs) =
    let major = Map.findKey(fun (major : Major) description -> major.Name = e.Item.SubItems.Item(0).Text) collegeMajors

    txtDescription.Text <- major.Degree
lvwMajors.ItemSelectionChanged.Add lvwMajorsSelectedIndexChanged

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

Another way to perform this operation is to try finding a key. This is done using the tryFindKey() function of the Map module. Its signature is:

Map.tryFindKey : ('Key -> 'T -> bool) -> Map<'Key,'T> -> 'Key option

Here is an example:

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

type Major(name, degree) =
    class
        member this.Name   = name
        member this.Degree = degree

        interface IComparable with
            member this.CompareTo(obj : Object) =
                match obj with
                | :? Major as maj -> compare this.Name maj.Name
                | _ -> 0

        override this.GetHashCode() = this.GetHashCode()
        override this.Equals(obj) =
                match obj with
                | :? Major as maj -> this.Name = maj.Name
                | _ -> false
    end

let collegeMajors = Map [ (new Major("Linguistics", "B.A."), "Scientific studies of human languages")
                          (new Major("Biology", "B.S."), "Study and understanding of functions and diversity of living organims")
                          (new Major("Chemistry", "B.S."), "Study of matter and changes in matter")
                          (new Major("Earth Science", "B.A."), "Basic chemical processes operating in and on the planet")
                          (new Major("Mechanical Engineering and Applied Mechanics", "B.S."), "Components manufacturing, machines and energy conversion")
                          (new Major("Economics", "B.A."), "Studies of the allocation of scarce resources")
                          (new Major("Computer Engineering", "B.S."), "Design and engineering of computer systems")
                          (new Major("Computer Science", "B.S."), "Computer principles, software systems design, and application development")
                          (new Major("Electrical Engineering", "B.S."), "Study and development of technonogies to create devices using electricity")
                          (new Major("Political Science", "B.A."), "Development of systematic approaches to the understanding of politics")
                          (new Major("Philosophy", "B.A."), "Fundamental aspects of, relations to, and knowledge of, the world")
                          (new Major("Psychology", "B.A."), "Combination of social and natural sciences approaches to the mind and behavior of organisms") ]

let university = new Form(MaximizeBox = false, Text = "State University",
                         ClientSize = new System.Drawing.Size(325, 255),
                         StartPosition = FormStartPosition.CenterScreen)

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

let mutable col = lvwMajors.Columns.Add("Major", 240)
col <- lvwMajors.Columns.Add("Degree", 50, HorizontalAlignment.Center)

university.Controls.Add lvwMajors

let txtDescription = new TextBox(Location = new Point(12, 220),
                                 Size = new System.Drawing.Size(300, 36),
                                 Anchor = (AnchorStyles.Left ||| AnchorStyles.Right ||| AnchorStyles.Bottom))
university.Controls.Add txtDescription

collegeMajors |> Map.iter (fun major description ->
    let lviMajor = new ListViewItem(sprintf "%s"  major.Name)
    lviMajor.SubItems.Add(sprintf "%s" major.Degree) |> ignore
    lvwMajors.Items.Add lviMajor |> ignore)

let engineering = Map.tryFindKey(fun (major : Major) description -> major.Name.ToLower().Contains("engineering")) collegeMajors

match engineering with
| Some major -> txtDescription.Text <- sprintf "%s" major.Name
| None -> ()

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

This would produce:

Introduction to Finding an Element in a Map

Checking Whether a Map Contains a Certain Key

To let you find out whether a map contains a certain key, the Map class is equipped with a method named ContainsKey. Its signature is:

member this.ContainsKey : 'Key -> bool

Here is an example of calling it:

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

let sdlc = (((Map [ (1, "Planning") ]).Add (2, "Analysis")).Add (3, "Design")).Add (4, "Implementation")

let applicationDevelopment = new Form(MaximizeBox = false,
                                      Text = "Software Development Life Cycle",
                                      ClientSize = new System.Drawing.Size(275, 125),
                                      StartPosition = FormStartPosition.CenterScreen)

let cbxPhases = new ComboBox(Location = new Point(12, 12), Width = 250)
applicationDevelopment.Controls.Add cbxPhases

cbxPhases.Items.Add ("1. Planning") |> ignore
cbxPhases.Items.Add ("2. Analysis") |> ignore
cbxPhases.Items.Add ("3. Design") |> ignore
cbxPhases.Items.Add ("4. Implementation") |> ignore
cbxPhases.Items.Add ("5. Requirements") |> ignore
cbxPhases.Items.Add ("6. Tests") |> ignore
cbxPhases.Items.Add ("7. Maintenance") |> ignore

let cbxPhasesSelectedIndexChanged e =
    if sdlc.ContainsKey (cbxPhases.SelectedIndex + 1) then
        MessageBox.Show("Our Software Development Life Cycle (SDLC) contains that key.", "Application Development", MessageBoxButtons.OK, MessageBoxIcon.Information) |> ignore
    else
        MessageBox.Show("That key does not exist in our Software Development Life Cycle (SDLC).", "Application Development", MessageBoxButtons.OK, MessageBoxIcon.Information) |> ignore
    
cbxPhases.SelectedIndexChanged.Add cbxPhasesSelectedIndexChanged

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

The Map module provides an equivalent function named containsKey. Its signature is:

Map.containsKey : 'Key -> Map<'Key,'T> -> bool

This function works the same way as the class's version.

Checking Whether an Element Exists in a Map

To let you find out whether a certain key exists in a map, the Map module provides a function named exists. Its signature is:

Map.exists : ('Key -> 'T -> bool) -> Map<'Key,'T> -> bool

This function takes two arguments. The first is a function that would apply a condition to the elements of a map, one after another. The second argument is the map on which the function will act. The function would return true if it finds an element that responds to the condition. Otherwise it would return false. Here is an example:

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

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

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

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

chemistry.Controls.Add(new Label(AutoSize = true,
                                 Location = new Point(14, 17),
                                 Text = "Enter Atomic #:"))
let txtAtomicNumber = new TextBox(TextAlign = HorizontalAlignment.Right,
                                  Location = new Point(100, 14), Width = 34)
chemistry.Controls.Add txtAtomicNumber

let btnVerify = new Button(Location = new Point(140, 13), Text = "Verify")
chemistry.Controls.Add btnVerify

let btnVerifyClick e =
    let exists = Map.exists (fun number element -> number = int txtAtomicNumber.Text) periodicTable

    if exists = true then
        MessageBox.Show("The element exists already.", "Periodic Table",
                        MessageBoxButtons.OK, MessageBoxIcon.Information) |> ignore
    else
        MessageBox.Show("There is no element with that number.", "Periodic Table",
                        MessageBoxButtons.OK, MessageBoxIcon.Information) |> ignore

btnVerify.Click.Add btnVerifyClick
  
[<EntryPoint>]
let main argv = 
    Application.Run chemistry
    0

Here is an example of excuting the program:

Checking Whether an Element Exists in a Map

Here is another example of excuting the program:

Checking Whether an Element Exists in a Map

Operations on a Map

 

Creating an Empty Map

For any you think necessary, you may need to create an empty map. To do this, you can use empty square brackets when initializing the variable that holds the map. Here is an example:

let layers = Map []

As an alternative, to let you create an empty map, the Map module provides a function named empty. Here is an example of using it to create an empty map:

type EarthLayer = {
    Name        : string
    Thickness   : string
    Composition : string array
    EarthMass   : string }

let layers = Map.empty

Adding an Item to a Map

You can either specify the items of a map when creating it as we have done so far, or you can add one or more new items to an existing map. Adding an element to a map is referred to as binding the element to the map.

To let you bind an element, the Map class is equipped with a method named Add. Its signature is:

member this.Add : 'Key * 'Value -> Map<'Key, 'Value>

In addition, the Map module is equipped with a function named add. Its signature is:

Map.add : 'Key -> 'T -> Map<'Key,'T> -> Map<'Key,'T>

In both cases, you must provide the key and the value as the first and second arguments. When the Map.Add() method or the Mad.add() functiuon is called, it produces a new map. You can store the new map in a variable and use it. Here are examples of calling the Map.Add() method:

let SDLCPhase1 = Map [ (1, "Planning") ]

let phases1And2 = SDLCPhase1.Add (2, "Analysis")
let phases1To3 = phases1And2.Add (3, "Design")
let sdlc = phases1To3.Add (4, "Implementation")

Since the method or function returns a new map, you can call the method or function on such a new map. Here are examples:

let sdlc = (((Map [ (1, "Planning") ]).Add (2, "Analysis")).Add (3, "Design")).Add (4, "Implementation")

A Mutable Map

Like all F# collection classes, by default, a map is immutable, meaning once you have created it, you cannot modify it. As an alternative and if you plan to keep adding elements to a map, you can make its variable mutable. This would allow you to add a new element by assigning the variable to itself. Here is an example:

type EarthLayer = {
    Name        : string
    Thickness   : string
    Composition : string array
    EarthMass   : string }

let mutable layers = Map []

layers <- layers.Add ('A', { Name = "Inner Core"; Thickness = "800 Miles"; Composition = [| "Iron (Fe)" |]; EarthMass = "1.7" })
layers <- layers.Add ('B', { Name = "Outer Core"; Thickness = "1400 Miles"; Composition = [| "Iron (Fe)"; "Sulfur (S)"; "Oxygen (O)" |]; EarthMass = "30.8%" })
layers <- layers.Add ('C', { Name = "Mantle"; Thickness = "1800 Miles"; Composition = [| "Iron (Fe)"; "Magnesium (Mg)"; "Aluminium (Al)"; "Silicon (Si)"; "Oxygen (O)" |]; EarthMass = "67.3%" })
layers <- layers.Add ('D', { Name = "Crust"; Thickness = "3-25 Miles"; Composition = [| "Calcium (Ca)"; "Sodium(Na)" |]; EarthMass = "0.0473%" })

Converting a Map to Another Type of Collection

The Map module provides various functions that can be used to convert a map into any type of F# collection:

Filtering Some Elements

Filtering a map consists of selecting only the elements that respond to a certain condition. To support this, the Map module provides a function named filter. Its signature is:

Map.filter : ('Key -> 'T -> bool) -> Map<'Key,'T> -> Map<'Key,'T>

This function takes two arguments. The first argument is a function and the second argument is the map. The function parameter takes two arguments. The first is the key side of the map. The second is the value side of the map. The body of the function parameter is a condition to apply to each key of the map. Every key that validates the condition is added to a new map produced from calling the function. Here is an example:

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

type Major(name, degree) =
    class
        member this.Name   = name
        member this.Degree = degree

        interface IComparable with
            member this.CompareTo(obj : Object) =
                match obj with
                | :? Major as maj -> compare this.Name maj.Name
                | _ -> 0

        override this.GetHashCode() = this.GetHashCode()
        override this.Equals(obj) =
                match obj with
                | :? Major as maj -> this.Name = maj.Name
                | _ -> false
    end

let collegeMajors = Map [ (new Major("Linguistics", "B.A."), "Scientific studies of human languages")
                          (new Major("Biology", "B.S."), "Study and understanding of functions and diversity of living organims")
                          (new Major("Chemistry", "B.S."), "Study of matter and changes in matter")
                          (new Major("Earth Science", "B.A."), "Basic chemical processes operating in and on the planet")
                          (new Major("Mechanical Engineering and Applied Mechanics", "B.S."), "Components manufacturing, machines and energy conversion")
                          (new Major("Economics", "B.A."), "Studies of the allocation of scarce resources")
                          (new Major("Computer Engineering", "B.S."), "Design and engineering of computer systems")
                          (new Major("Computer Science", "B.S."), "Computer principles, software systems design, and application development")
                          (new Major("Electrical Engineering", "B.S."), "Study and development of technonogies to create devices using electricity")
                          (new Major("Political Science", "B.A."), "Development of systematic approaches to the understanding of politics")
                          (new Major("Philosophy", "B.A."), "Fundamental aspects of, relations to, and knowledge of, the world")
                          (new Major("Psychology", "B.A."), "Combination of social and natural sciences approaches to the mind and behavior of organisms") ]

let university = new Form(MaximizeBox = false, Text = "State University",
                         ClientSize = new System.Drawing.Size(325, 270),
                         StartPosition = FormStartPosition.CenterScreen)

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

let mutable col = lvwMajors.Columns.Add("Major", 240)
col <- lvwMajors.Columns.Add("Degree", 50, HorizontalAlignment.Center)

university.Controls.Add lvwMajors

let txtDescription = new TextBox(Size = new System.Drawing.Size(300, 36),
                                 Multiline = true, Location = new Point(12, 220),
                                 Anchor = (AnchorStyles.Left ||| AnchorStyles.Right ||| AnchorStyles.Bottom))
university.Controls.Add txtDescription

let BSDegrees = Map.filter(fun (major : Major) description -> major.Degree = "B.S.") collegeMajors

BSDegrees |> Map.iter (fun major description ->
    let lviMajor = new ListViewItem(sprintf "%s"  major .Name)
    lviMajor.SubItems.Add(sprintf "%s" major.Degree) |> ignore
    lvwMajors.Items.Add lviMajor |> ignore)

let lvwMajorsSelectedIndexChanged(e : ListViewItemSelectionChangedEventArgs) =
    for major in collegeMajors do
        if major.Key.Name = e.Item.SubItems.Item(0).Text then
            txtDescription.Text <- major.Value

lvwMajors.ItemSelectionChanged.Add lvwMajorsSelectedIndexChanged

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

This would produce:

Filtering Some Elements

Checking Whether a Condition Applies to All Elements

To let you find out whether a certain condition applies to all elements or all elements follow a certain pattern, the Map module provides the forAll() function. Its signature is:

Map.forall : ('Key -> 'T -> bool) -> Map<'Key,'T> -> bool

This function applies a condition of your choice to each element of the map. The function does this through the first parameter passed as a function that acts on the second parameter. If each lement of the map verifies the condition, the function returns true. Otherwise, it returns false. Here is an example:

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

let atmosphere = new Form(MaximizeBox = false,
                          Text = "Atmosphere Layers",
                          ClientSize = new System.Drawing.Size(360, 130),
                          StartPosition = FormStartPosition.CenterScreen)

let lbxLayers : ListBox = new ListBox(Location = new Point(14, 17),
                                      Size = new System.Drawing.Size(330, 75))
atmosphere.Controls.Add lbxLayers

let layers = Map [ ("A5. Exosphere",    "Satellites")
                   ("B4. Thermosphere", "Absorption of Ultraviolet and X-Ray Radiations")
                   ("C3. Mesosphere",   "Slow Down of Meteors")
                   ("D2. Stratosphere", "Ozone layer")
                   ("E1. Troposphere",  "Clouds, Air, and Weather") ]

let lblMessage = new Label(Location = new Point(12, 100),
                           AutoSize = true, Text = "Message")
atmosphere.Controls.Add lblMessage

let mutable i = 0

for layer in layers do
    i <- lbxLayers.Items.Add(sprintf "%s\t%s" layer.Key layer.Value)

let all = layers |> Map.forall(fun layer descrption -> layer.EndsWith("sphere"))

if all = true then
    lblMessage.Text <- "All layers' names end with \"sphere\""
else
    lblMessage.Text <- "At least one layer name doesn't end with \"sphere\""

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

This would produce:

Checking Whether a Condition Applies to All Elements

Mapping a Map

Mapping consits of applying a condition to each element of a map. The operation produces a new map that contains all the elements of the original map in their modified versions. To support this operation, the Map module provides a function named map. Its signature is:

Map.map : ('Key -> 'T -> 'U) -> Map<'Key,'T> -> Map<'Key,'U>

Here is an example:

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

type Major(name, degree) =
    class
        let mutable d = degree

        member this.Name   = name
        member this.Degree with get() = d and set(value) = d <- value

        interface IComparable with
            member this.CompareTo(obj : Object) =
                match obj with
                | :? Major as maj -> compare this.Name maj.Name
                | _ -> 0

        override this.GetHashCode() = this.GetHashCode()
        override this.Equals(obj) =
                match obj with
                | :? Major as maj -> this.Name = maj.Name
                | _ -> false
    end

let collegeMajors = Map [ (new Major("Linguistics", "B.A."), "Scientific studies of human languages")
                          (new Major("Biology", "B.S."), "Study and understanding of functions and diversity of living organims")
                          (new Major("Chemistry", "B.S."), "Study of matter and changes in matter")
                          (new Major("Earth Science", "B.A."), "Basic chemical processes operating in and on the planet")
                          (new Major("Mechanical Engineering and Applied Mechanics", "B.S."), "Components manufacturing, machines and energy conversion")
                          (new Major("Economics", "B.A."), "Studies of the allocation of scarce resources")
                          (new Major("Computer Engineering", "B.S."), "Design and engineering of computer systems")
                          (new Major("Computer Science", "B.S."), "Computer principles, software systems design, and application development")
                          (new Major("Electrical Engineering", "B.S."), "Study and development of technonogies to create devices using electricity")
                          (new Major("Political Science", "B.A."), "Development of systematic approaches to the understanding of politics")
                          (new Major("Philosophy", "B.A."), "Fundamental aspects of, relations to, and knowledge of, the world")
                          (new Major("Psychology", "B.A."), "Combination of social and natural sciences approaches to the mind and behavior of organisms") ]

let studies = Map.map(fun (major : Major) description ->
    if major.Degree = "B.A." then major.Degree <- "Bachelor of Art"
    else major.Degree <- "Bachelor of Science") collegeMajors

let university = new Form(MaximizeBox = false, Text = "State University",
                         ClientSize = new System.Drawing.Size(385, 270),
                         StartPosition = FormStartPosition.CenterScreen)

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

let mutable col = lvwMajors.Columns.Add("Major", 240)
col <- lvwMajors.Columns.Add("Degree", 110)

university.Controls.Add lvwMajors

let txtDescription = new TextBox(Size = new System.Drawing.Size(360, 36),
                                 Multiline = true, Location = new Point(12, 220),
                                 Anchor = (AnchorStyles.Left ||| AnchorStyles.Right ||| AnchorStyles.Bottom))
university.Controls.Add txtDescription

studies |> Map.iter (fun major description ->
    let lviMajor = new ListViewItem(sprintf "%s"  major .Name)
    lviMajor.SubItems.Add(sprintf "%s" major.Degree) |> ignore
    lvwMajors.Items.Add lviMajor |> ignore)

let lvwMajorsSelectedIndexChanged(e : ListViewItemSelectionChangedEventArgs) =
    for major in collegeMajors do
        if major.Key.Name = e.Item.SubItems.Item(0).Text then
            txtDescription.Text <- major.Value

lvwMajors.ItemSelectionChanged.Add lvwMajorsSelectedIndexChanged

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

This would produce:

Mapping a Map

Partitioning a Map

Partitioning a map consists of getting two sub-lists from that map, based on a condition. To support this operation, the Map module provides a function named partition. Its signature is:

Map.partition : ('Key -> 'T -> bool) -> Map<'Key,'T> -> Map<'Key,'T> * Map<'Key,'T>

This function takes two arguments. The first argument is a function and and the second is the map that holds the original elements. The function parameter takes two arguments as the key and the value of an element of the map. The function must apply a Boolean operation on each element of the map. The elements that respond to the condition are put into a first map. The elements that don't respond to the condition are put in a second list. This means that the function returns two maps. Here is an example:

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

type PhysicalCharacteristic =
| Metal
| Metalloid
| NonMetal
| Unknown

type ChemicalElement = {
    Name         : string
    Symbol       : string
    AtomicMass   : string
    Category     : PhysicalCharacteristic  }

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

let metals, others = Map.partition(fun number (element : ChemicalElement) -> element.Category = Metal) periodicTable

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

chemistry.Controls.Add(new Label(AutoSize = true, Location = new Point(12, 12), Text = "Metals"))

let lvwMetals = new ListView(GridLines = true, View = View.Details,
                               Size = new System.Drawing.Size(358, 56),
                               FullRowSelect = true, Location = new Point(12, 32))

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

chemistry.Controls.Add(new Label(AutoSize = true, Location = new Point(12, 96), Text = "Other Chemical Elements"))

let lvwOtherElements = new ListView(GridLines = true, View = View.Details,
                                    Size = new System.Drawing.Size(358, 140),
                                    FullRowSelect = true, Location = new Point(12, 116))

col <- lvwOtherElements.Columns.Add("Atomic Number", 85)
col <- lvwOtherElements.Columns.Add("Name", 70)
col <- lvwOtherElements.Columns.Add("Symbol", 50, HorizontalAlignment.Center)
col <- lvwOtherElements.Columns.Add("Atomic Mass", 75, HorizontalAlignment.Right)
col <- lvwOtherElements.Columns.Add("Category", 70)
chemistry.Controls.Add lvwOtherElements

if not metals.IsEmpty then
    metals |> Map.iter (fun number (element : ChemicalElement) ->
    let mutable lviElement = new ListViewItem()
    lviElement.Text <- (sprintf "%i" number)
    lviElement.SubItems.Add (sprintf "%s" element.Name) |> ignore
    lviElement.SubItems.Add (sprintf "%s" element.Symbol) |> ignore
    lviElement.SubItems.Add (sprintf "%s" element.AtomicMass) |> ignore
    lviElement.SubItems.Add (sprintf "%A" element.Category) |> ignore
    lvwMetals.Items.Add lviElement |> ignore)

if not others.IsEmpty then
    others |> Map.iter (fun number (element : ChemicalElement) ->
    let mutable lviElement = new ListViewItem()
    lviElement.Text <- (sprintf "%i" number)
    lviElement.SubItems.Add (sprintf "%s" element.Name) |> ignore
    lviElement.SubItems.Add (sprintf "%s" element.Symbol) |> ignore
    lviElement.SubItems.Add (sprintf "%s" element.AtomicMass) |> ignore
    lviElement.SubItems.Add (sprintf "%A" element.Category) |> ignore
    lvwOtherElements.Items.Add lviElement |> ignore)

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

This would produce:

Partitioning a Map

In the same way, you can create various partitions from the same map. Here are examples:

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

type PhysicalCharacteristic =
| Metal
| Metalloid
| NonMetal
| Unknown

type ChemicalElement = {
    Name         : string
    Symbol       : string
    AtomicMass   : string
    Category     : PhysicalCharacteristic  }

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

let metals, nonMetals = Map.partition(fun number (element : ChemicalElement) -> element.Category = Metal) periodicTable
let metalloids, others = Map.partition(fun number (element : ChemicalElement) -> element.Category = Metalloid) nonMetals

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

chemistry.Controls.Add(new Label(AutoSize = true, Location = new Point(12, 12), Text = "Metals"))

let lvwMetals = new ListView(GridLines = true, View = View.Details,
                               Size = new System.Drawing.Size(358, 56),
                               FullRowSelect = true, Location = new Point(12, 32))

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

chemistry.Controls.Add(new Label(AutoSize = true, Location = new Point(12, 96), Text = "Metalloids"))

let lvwMetalloids = new ListView(GridLines = true, View = View.Details,
                                    Size = new System.Drawing.Size(358, 40),
                                    FullRowSelect = true, Location = new Point(12, 116))

col <- lvwMetalloids.Columns.Add("Atomic Number", 85)
col <- lvwMetalloids.Columns.Add("Name", 70)
col <- lvwMetalloids.Columns.Add("Symbol", 50, HorizontalAlignment.Center)
col <- lvwMetalloids.Columns.Add("Atomic Mass", 75, HorizontalAlignment.Right)
col <- lvwMetalloids.Columns.Add("Category", 70)
chemistry.Controls.Add lvwMetalloids

chemistry.Controls.Add(new Label(AutoSize = true, Location = new Point(12, 166), Text = "Other Chemical Elements"))

let lvwOtherElements = new ListView(GridLines = true, View = View.Details,
                                    Size = new System.Drawing.Size(358, 125),
                                    FullRowSelect = true, Location = new Point(12, 186))

col <- lvwOtherElements.Columns.Add("Atomic Number", 85)
col <- lvwOtherElements.Columns.Add("Name", 70)
col <- lvwOtherElements.Columns.Add("Symbol", 50, HorizontalAlignment.Center)
col <- lvwOtherElements.Columns.Add("Atomic Mass", 75, HorizontalAlignment.Right)
col <- lvwOtherElements.Columns.Add("Category", 70)
chemistry.Controls.Add lvwOtherElements

if not metals.IsEmpty then
    metals |> Map.iter (fun number (element : ChemicalElement) ->
    let mutable lviElement = new ListViewItem()
    lviElement.Text <- (sprintf "%i" number)
    lviElement.SubItems.Add (sprintf "%s" element.Name) |> ignore
    lviElement.SubItems.Add (sprintf "%s" element.Symbol) |> ignore
    lviElement.SubItems.Add (sprintf "%s" element.AtomicMass) |> ignore
    lviElement.SubItems.Add (sprintf "%A" element.Category) |> ignore
    lvwMetals.Items.Add lviElement |> ignore)

if not metalloids.IsEmpty then
    metalloids |> Map.iter (fun number (element : ChemicalElement) ->
    let mutable lviElement = new ListViewItem()
    lviElement.Text <- (sprintf "%i" number)
    lviElement.SubItems.Add (sprintf "%s" element.Name) |> ignore
    lviElement.SubItems.Add (sprintf "%s" element.Symbol) |> ignore
    lviElement.SubItems.Add (sprintf "%s" element.AtomicMass) |> ignore
    lviElement.SubItems.Add (sprintf "%A" element.Category) |> ignore
    lvwMetalloids.Items.Add lviElement |> ignore)

if not others.IsEmpty then
    others |> Map.iter (fun number (element : ChemicalElement) ->
    let mutable lviElement = new ListViewItem()
    lviElement.Text <- (sprintf "%i" number)
    lviElement.SubItems.Add (sprintf "%s" element.Name) |> ignore
    lviElement.SubItems.Add (sprintf "%s" element.Symbol) |> ignore
    lviElement.SubItems.Add (sprintf "%s" element.AtomicMass) |> ignore
    lviElement.SubItems.Add (sprintf "%A" element.Category) |> ignore
    lvwOtherElements.Items.Add lviElement |> ignore)

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

This would produce:

Partitioning a Map

Removing an Element From a Map

To let you delete an element from a map, the Map class is equipped with a method named Remove. Its signature is:

member this.Remove : 'Key -> Map<'Key, 'Value>

This method takes one argument is the key. If the compiler finds an element with that key, it deletes that element and returns a new map that is from the existing map minus the undesired one. Here is an example of calling this method:

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

type EarthLayer = {
    Name        : string
    Thickness   : string
    Composition : string array
    EarthMass   : string }

let mutable layers = Map.empty

layers <- layers.Add ('A', { Name = "Inner Core"; Thickness = "800 Miles"; Composition = [| "Iron (Fe)" |]; EarthMass = "1.7" })
layers <- layers.Add ('B', { Name = "Outer Core"; Thickness = "1400 Miles"; Composition = [| "Iron (Fe)"; "Sulfur (S)"; "Oxygen (O)" |]; EarthMass = "30.8%" })
layers <- layers.Add ('C', { Name = "Mantle"; Thickness = "1800 Miles"; Composition = [| "Iron (Fe)"; "Magnesium (Mg)"; "Aluminium (Al)"; "Silicon (Si)"; "Oxygen (O)" |]; EarthMass = "67.3%" })
layers <- layers.Add ('D', { Name = "Crust"; Thickness = "3-25 Miles"; Composition = [| "Calcium (Ca)"; "Sodium(Na)" |]; EarthMass = "0.0473%" })
layers <- layers.Add ('E', { Name = "Air"; Thickness = "6500 Miles"; Composition = [| "Oxygen (O)"; "Carbon(C)" |]; EarthMass = "Unknown" })

let planetEarth = new Form(MaximizeBox = false, Text = "Planet Earth",
                           ClientSize = new System.Drawing.Size(620, 300),
                           StartPosition = FormStartPosition.CenterScreen)

let lvwLayers = new ListView(GridLines = true, View = View.Details,
                             Size = new System.Drawing.Size(588, 95),
                             FullRowSelect = true, Location = new Point(12, 12))

let mutable col = lvwLayers.Columns.Add("Level", 45)
col <- lvwLayers.Columns.Add("Name", 70)
col <- lvwLayers.Columns.Add("Thickness", 65, HorizontalAlignment.Right)
col <- lvwLayers.Columns.Add("Composition", 330)
col <- lvwLayers.Columns.Add("Earth Mass", 70, HorizontalAlignment.Right)
planetEarth.Controls.Add lvwLayers

let btnRemoveAir = new Button(Size = new System.Drawing.Size(588, 28),
                              Location = new Point(12, 120), Text = "Remove Air")
planetEarth.Controls.Add btnRemoveAir

let lvwActualLayers = new ListView(GridLines = true, View = View.Details,
                                   Size = new System.Drawing.Size(588, 83),
                                   FullRowSelect = true, Location = new Point(12, 160))

col <- lvwActualLayers.Columns.Add("Level", 45)
col <- lvwActualLayers.Columns.Add("Name", 70)
col <- lvwActualLayers.Columns.Add("Thickness", 65, HorizontalAlignment.Right)
col <- lvwActualLayers.Columns.Add("Composition", 330)
col <- lvwActualLayers.Columns.Add("Earth Mass", 70, HorizontalAlignment.Right)
planetEarth.Controls.Add lvwActualLayers

Map.iter (fun number (layer : EarthLayer) ->
    let  mutable elements = ""
    let mutable lviLayer = new ListViewItem()
    lviLayer.Text <- (sprintf "%c" number)
    lviLayer.SubItems.Add (sprintf "%s" layer.Name) |> ignore
    lviLayer.SubItems.Add (sprintf "%s" layer.Thickness) |> ignore

    let mutable strLayer = ""
    for str in layer.Composition do
        strLayer <- strLayer + str + ", "
    elements <- strLayer.Substring(0, strLayer.Length - 2)
    lviLayer.SubItems.Add (sprintf "%s" elements) |> ignore
    lviLayer.SubItems.Add (sprintf "%s" layer.EarthMass) |> ignore
    lvwLayers.Items.Add lviLayer |> ignore) layers

let btnRemoveAirClick _ =
    let actualLayers = layers.Remove 'E'

    Map.iter (fun number (layer : EarthLayer) ->
        let  mutable elements = ""
        let mutable lviLayer = new ListViewItem()
        lviLayer.Text <- (sprintf "%c" number)
        lviLayer.SubItems.Add (sprintf "%s" layer.Name) |> ignore
        lviLayer.SubItems.Add (sprintf "%s" layer.Thickness) |> ignore

        let mutable strLayer = ""
        for str in layer.Composition do
            strLayer <- strLayer + str + ", "
        elements <- strLayer.Substring(0, strLayer.Length - 2)
        lviLayer.SubItems.Add (sprintf "%s" elements) |> ignore
        lviLayer.SubItems.Add (sprintf "%s" layer.EarthMass) |> ignore
        lvwActualLayers.Items.Add lviLayer |> ignore) actualLayers
btnRemoveAir.Click.Add btnRemoveAirClick

let btnClose = new Button(Size = new System.Drawing.Size(588, 28),
                          Location = new Point(12, 255), Text = "Close")
let btnCloseClick _ = planetEarth.Close()
btnClose.Click.Add btnCloseClick
planetEarth.Controls.Add btnClose

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

This would produce:

Removing an Element From a Map

Removing an Element From a Map

If there is no element with the key passed as argument, the method simply returns the original list.


Home Copyright © 2010-2015 FunctionX Home