Home

F# Collections: Arrays

 

Fundamentalsof Arrays

 

Introduction

A technique used to create an array collection is:

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

let exercise = new Form(ClientSize = new System.Drawing.Size(210, 57), Text = "Numbers")

let lblNumbers = new Label(Location = new Point(21, 18), Width = 258)

let numbers = [| 44; 2; 186; 97; 394 |]

let strNumbers = sprintf "Numbers: %A" numbers

lblNumbers.Text <- strNumbers

exercise.Controls.Add lblNumbers

[<EntryPoint>]
let main arguments =
    Application.Run exercise
    0

This would produce:

Creating a Collection

In reality, this is just one technique of creating a collection. As a matter of fact, the above type of collection is called an array. An array is a list of values where:

  • Each item is known in advance and must be specified at the time the array is created
  • All items are of the same type. They could all be numbers. They could all be strings. They could all be objects of the same class. If you mix items of different types, you would receive an error
  • Because all items are known in advance, the number of items (called the length) of the array is also known and is fixed. This means that, after the array has been created, you cannot add new elements to it
  • Each item occupies a specific position known as its index (the index of the item)
  • The array is mutable. This means that, at any time, you can change the value of any element in the array, based on the index of that element
  • The positions (indexes) of the items start at 0 up to the length - 1

Introduction to Creating an Array

There are many options to create an array. The fundamental principle is that the items or elements of an array are included inside the [| and the |] operators. Therefore, to create an array of specifically known values, the formula to follow is:

[| Member1; Member2; Member_n |]

With this formula, inside the operators, specify the value of each item. The items are separated by semicolons. Here is an example:

[| "James"; "Annette"; "Hughs"; "Daniel" "Martine" |]

The array members don't have to be on the same line; you can put them on different lines. Here is an example:

[|
"James";
"Annette";
"Hughs";
"Daniel"
"Martine"
|]

If you do this, you can omit the semicolons. Also, to make your code easy to read, you should indent the items (but this is not a requirement):

[|
    "James"
    "Annette"
    "Hughs"
    "Daniel"
    "Martine"
|]

If your array consists of consecutive ASCII characters, consecutive alphabetical letters, or incrementing numbers, you can specify its values as a range. In this case, inside the operators, the formula to follow is:

StartValue .. EndValue

Here is an example:

[| 'e' .. 'l' |]

If your array consists of consecutive numbers that follow a common skipping scheme, you can specify its values using a skip range. To do this, inside the operators, the formula to follow is:

Start .. Step .. End

Here is an example:

[| 0 .. 2 .. 20 |]

Naming an Array

To refer to an array as one, you can store it in a variable. This is done using the let keyword followed by a name for the variable, and assigning the array. Here are examples:

let names       = [| "James"; "Annette"; "Hughs"; "Daniel"; "Martine" |]
let letters     = [| 'e' .. 'l' |]
let evenNumbers = [| 0 .. 2 .. 20 |]

The Data Type of an Array

When you create an array, the compiler infers the type of values the array contains. In some cases, you will want to use a type other than the one the compiler thinks you are using. In some other cases, you will want to explicitly indicate the type of values of the array members.

To specify the data type of an array, after the name of the variable, type : followed the data type and the array word. Here are examples:

let names : string array   = [| "James"; "Annette"; "Hughs"; "Daniel"; "Martine" |]
let letters : char array   = [| 'a' .. 'f' |]

Accessing the Members of an Array

 

Accessing Each Item

To display an array and all its members, you can use %A in the placeholder of sprintf. To access each individual item of an array, you can use a for loop. The formula to follow is:

for identifier in array Or ArrayName do
   body

Since all items are of the same type, use the appropriate character in the placeholder of the sprintf()  function. Here is an example:

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

let torontoSubway : Form = new Form(MaximizeBox = false, StartPosition = FormStartPosition.CenterScreen,
                                    Text = "Toronto Subway", ClientSize = new System.Drawing.Size(175, 102)) 

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

let mutable i = 0

for n in [| "Kipling"; "Islington"; "Royal York"; "Old Mill"; "Jane" |] do
    i <- lbxStations.Items.Add n

torontoSubway.Controls.Add lbxStations

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

This would produce:

Accessing Each Item

Accessing An Item by its Index

As mentioned in the begining, each member of an array occupies a specific position know as its index. The first item has an index as 0, the second has an index as 1, the third as an index as 2, and so on. To access an item, you apply the square brackets to the name of the array. The formula to go from the begining to the end of the array is:

for identifier = start to end do
   body

In the body of the loop, access each looping item using the following formula:

ArrayName.[identifier]

Based on the earlier description, if you have an array named courses and it has 6 items, to access the third, you would use courses.[2]. Here are examples:

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

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

let lbxZones = new ListBox(Location = new Point(12, 17),
                           Size = new System.Drawing.Size(200, 130))

let zones = [| "Pacific Standard Time (PST)"
               "Mountain Standard Time (MST)"
               "Central Standard Time (CST)"
               "Eastern Standard Time (EST)"
               "Atlantic Standard Time (AST)"
               "Alaskan Standard Time (AKST)"
               "Hawaii-Aleutian Standard Time (HST)"
               "Samoa standard time (UTC-11)"
               "Chamorro Standard Time (UTC+10)" |]

let mutable n = 0

for i = 0 to 8 do
    n <- lbxZones.Items.Add (sprintf "%s" zones.[i])

USTimeZones.Controls.Add lbxZones

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

This would produce:

Accessing Each Item

Accessing the Items in a Range

You can consider that an array is a series of ranges of values, from the begining of the array to a certain item, from a certain item to another in a range, and from a certain item to the end. This means that, when it comes to ranges in the array, you have three options.

To access the range of items from the begining to a specific index, the formula to follow is:

ArrayName.[..Index]

Here is an example:

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

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

let zones = [| "Pacific Standard Time (PST)"
               "Mountain Standard Time (MST)"
               "Central Standard Time (CST)"
               "Eastern Standard Time (EST)"
               "Atlantic Standard Time (AST)"
               "Alaskan Standard Time (AKST)"
               "Hawaii-Aleutian Standard Time (HST)"
               "Samoa standard time (UTC-11)"
               "Chamorro Standard Time (UTC+10)" |]

USTimeZones.Controls.Add(new Label(Location = new Point(12, 17),
                                   Text = "All Time Zones", AutoSize = true))

let lbxAllTimeZones = new ListBox(Size = new Size(200, 130),
                                  Location = new Point(12, 41))

let mutable i = 0

for item in zones do
    i <- lbxAllTimeZones.Items.Add item

USTimeZones.Controls.Add lbxAllTimeZones

USTimeZones.Controls.Add(new Label(Location = new Point(12, 175),
                                   Text = "Continental Time Zones", AutoSize = true))

let lbxContinentals = new ListBox(Size = new Size(200, 67),
                                  Location = new Point(12, 198))

let continentals = zones.[ .. 3 ]

for item in continentals do
    i <- lbxContinentals.Items.Add item

USTimeZones.Controls.Add lbxContinentals

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

This would produce:

Accessing the Members in a Range

To access the items in a certain range, specify the starting index, two periods, and the ending index. The formula to follow is:

ArrayName.[StartIndex .. EndIndex]

Here are examples:

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

let USCensusBureauRegions = new Form(MaximizeBox = false, Text = "US Census Bureau - Regions",
                                     ClientSize = new Size(232, 265), StartPosition = FormStartPosition.CenterScreen)

let regions = [| "New England";
                 "Mid-Atlantic";
                 "East North Central";
                 "West North Central";
                 "South Atlantic";
                 "East South Central";
                 "West South Central";
                 "Mountain"
                 "Pacific" |]

USCensusBureauRegions.Controls.Add(new Label(Text = "All Regions and Divisions",
                                             Location = new Point(12, 14), AutoSize = true))

let lbxAllRegions = new ListBox(Size = new Size(205, 130), Location = new Point(12, 41))

let mutable i = 0

for item in regions do
    i <- lbxAllRegions.Items.Add item

USCensusBureauRegions.Controls.Add lbxAllRegions

USCensusBureauRegions.Controls.Add(new Label(Location = new Point(12, 170), Text = "South"))

let lbxSouth = new ListBox(Size = new Size(205, 60), Location = new Point(12, 195))

let south = regions.[ 3 .. 6 ]

for item in south do
    i <- lbxSouth.Items.Add item

USCensusBureauRegions.Controls.Add lbxSouth

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

This would produce:

Accessing Each Item

To access some items at the end of the array, inside the [| and the |] operators, specify the starting index and add two periods. The formula to follow is:

ArrayName.[StartIndex .. ]

Here are examples:

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

let USTimeZones = new Form(MaximizeBox = false,
                           Text = "United States Time Zonoes",
                           ClientSize = new System.Drawing.Size(228, 280),
                           StartPosition = FormStartPosition.CenterScreen)

let zones = [| "Pacific Standard Time (PST)"
               "Mountain Standard Time (MST)"
               "Central Standard Time (CST)"
               "Eastern Standard Time (EST)"
               "Atlantic Standard Time (AST)"
               "Alaskan Standard Time (AKST)"
               "Hawaii-Aleutian Standard Time (HST)"
               "Samoa standard time (UTC-11)"
               "Chamorro Standard Time (UTC+10)" |]

USTimeZones.Controls.Add(new Label(Location = new Point(12, 17),
                                   Text = "All Time Zones", AutoSize = true))

let lbxAllTimeZones = new ListBox(Size = new Size(200, 130),
                                  Location = new Point(12, 41))

let mutable i = 0

for item in zones do
    i <- lbxAllTimeZones.Items.Add item

USTimeZones.Controls.Add lbxAllTimeZones

USTimeZones.Controls.Add(new Label(Location = new Point(12, 175),
                                   Text = "Continental Time Zones", AutoSize = true))

let lbxNonContinentals = new ListBox(Size = new Size(200, 80),
                                  Location = new Point(12, 198))

let nonContinentals = zones.[ 4 .. ]

for item in nonContinentals do
    i <- lbxNonContinentals.Items.Add item

USTimeZones.Controls.Add lbxNonContinentals

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

This would produce:

Accessing Each Item

The Values of Items in an Array

 

An Empty Array

An array is considered empty if it doesn't contain any value. To create such an array, specify its value as [||]. To store that array in a variable, assign [||] to the variable. Here is an example:

let timesWorked = [||]

Even though the array is empty, you can access its value.

Checking Whether an Array is Empty

To let you find out whether an array is empty, you can use the match operator with an option as [||]. When that option is valid, the array is empty. You can use the underscore for the other option that indicates that the array has at least one element. Here are examples:

let numbers = [||]

match numbers with
| [||] -> // The array doesn't contain any element(s)
| _ -> // The array contains some element(s)

Setting the Values of Items

As mentioned already, when creating an array, you must provide the values of its items. Sometimes you don't have those values, maybe because they are not yet available. One solution is to provide sample values. The idea is to specify the number of items in the array. Here is an example:

let dailySales = [| 0.00; 0.00; 0.00; 0.00; 0.00; 0.00; 0.00; |]

Of course, the sample values depend on the type of values. Here is an example for string items:

let daysWorked = [| ""; ""; ""; ""; ""; ""; ""; |]

When you have done this, the compiler reserved a fixed area of the computer memory for the array and stores each item in the appropriate consecutive position. By definition, you cannot add new items to the array, but you can change the value stored in a certain position. To do this, access the item by its position using the .[] operator as we saw already. You can then assign the desired value using the mutable operator <-. Here are examples:

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

let dailySales = [| 0.00; 0.00; 0.00; 0.00; 0.00; 0.00; 0.00; |]
let daysWorked = [| ""; ""; ""; ""; ""; ""; ""; |]

dailySales.[0] <-  600.00
dailySales.[1] <-  750.00
dailySales.[2] <-  800.00
dailySales.[3] <-  450.00
dailySales.[4] <- 1050.00
dailySales.[5] <-    0.00
dailySales.[6] <-    0.00

daysWorked.[0] <- "Monday"
daysWorked.[1] <- "Tuesday"
daysWorked.[2] <- "Wednesday"
daysWorked.[3] <- "Thursday"
daysWorked.[4] <- "Frisday"
daysWorked.[5] <- "Saturday"
daysWorked.[6] <- "Sunday"

let bookCompany : Form = new Form(MaximizeBox = false, Text = "Book Company - Employees Sales", ClientSize = new System.Drawing.Size(378, 150), StartPosition = FormStartPosition.CenterScreen)

let lvwSales : ListView = new ListView(GridLines = true, View = View.Details, FullRowSelect = true, Location = new Point(12, 12), Size = new System.Drawing.Size(355, 122))

let mutable col = lvwSales.Columns.Add("Day Worked", 75)
col <- lvwSales.Columns.Add("Sales", 55, HorizontalAlignment.Right)
col <- lvwSales.Columns.Add("Commission Rate", 110, HorizontalAlignment.Center)
col <- lvwSales.Columns.Add("Commission Earned", 110, HorizontalAlignment.Center)

for n in [0 .. 6] do
    let commissionEarned = dailySales.[n] * 25.00 / 100.00

    let lviSale = new ListViewItem(sprintf "%s" daysWorked.[n])
    lviSale.SubItems.Add(sprintf "%0.02f" dailySales.[n]) |> ignore
    lviSale.SubItems.Add(sprintf "25%c" '%') |> ignore
    lviSale.SubItems.Add(sprintf "%0.02f" commissionEarned) |> ignore
    lvwSales.Items.Add lviSale |> ignore

bookCompany.Controls.Add lvwSales

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

This would produce:

Setting the Values of Items

Arrays and Functions

 

Returning an Array

You can create a function that manipulates some values, produces an array, and returns it. You can then call the function to get its returned array and use it as you see fit. Here is an example:

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

let businessDays = new Form(MaximizeBox = false, Text = "Days", ClientSize = new Size(127, 120), StartPosition = FormStartPosition.CenterScreen)

let daysWorked() = 
    let daysWorked = [| ""; ""; ""; ""; ""; ""; ""; |]

    daysWorked.[0] <- "Monday";
    daysWorked.[1] <- "Tuesday";
    daysWorked.[2] <- "Wednesday";
    daysWorked.[3] <- "Thursday";
    daysWorked.[4] <- "Frisday";
    daysWorked.[5] <- "Saturday";
    daysWorked.[6] <- "Sunday";

    // Array returned
    daysWorked

let days = daysWorked()

let lbxDays = new ListBox(Size = new Size(100, 100), Location = new Point(12, 12))

let mutable i = 0

businessDays.Controls.Add lbxDays

for d = 0 to 6 do
    i <- lbxDays.Items.Add days.[d]

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

This would produce:

Returning an Array

In the same way, you can pass one or more values to a function. The function can use the values to generate an array from its internal calculations. Here is an example:

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

let generateReciprocalInverses start finish =
    [| for n = start to finish - 1 do yield "-1/" + (string n) |] // Returned array

let reciprocalInverses = new Form(MaximizeBox = false, Text = "Numbers", ClientSize = new Size(195, 215), StartPosition = FormStartPosition.CenterScreen)

reciprocalInverses.Controls.Add(new Label(Location = new Point(12, 12), AutoSize = true, Height = 13, Text = "Receiprocal Inverses from 3 to 12"))

let lbxNumbers = new ListBox(Size = new Size(150, 170), Location = new Point(21, 32))
reciprocalInverses.Controls.Add lbxNumbers

let inverses = generateReciprocalInverses 3 12

let mutable i = 3

reciprocalInverses.Controls.Add lbxNumbers

lbxNumbers.Items.Add "\tReciprocal" |> ignore
lbxNumbers.Items.Add "Number\t   Inverse" |> ignore
lbxNumbers.Items.Add "---------------------------------------" |> ignore
for n in inverses do
    lbxNumbers.Items.Add(sprintf "      %i\t     %s" i n) |> ignore
    i <- i + 1

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

This produce:

Returning an Array

An Array as Parameter

An array can be passed as a parameter to a function. Consider the following example:

let showPayroll values =
    for time in values do
        sprintf "Time Worked: %0.02F" time

When calling the function, pass an array that holds the appropriate and desired values. Here is an example:

let timesWorked = [| 8.00; 8.50; 6.50; 7.50; 9.00; 0.00; 0.00; |]

let showPayroll values =
    for time in values do
        sprintf "Time Worked: %0.02F" time

showPayroll timesWorked

In the samy way, you can pass more than one array to a function.

Remember that F# is an inferred language. This means that when passing an array or many arrays to a function, the compiler may not know the type of value an array parameter holds. The parameter can be anything. If the compiler has any difficult figuring out the types of parameter, it would produce an error. Therefore, it is recommend that it indicate the type of the parameter.

A function can do more than simply displaying the values of an array it gets as parameter. It can use the values of that array, perform some calculations, and simply return a new value. A function can also get an array as parameter and return an array.

     
 

Arrays and Records

 

An Array of Records

The items of an array can come from a record. Of course, you must have a record. You can create various objects and add each to an array. Here is an example:

type RoadSystem = {
    RoadName : string
    Category : RoadType
    Distance : float
    Location : string }
        
let roadMD410 = { RoadName = "MD 410"; Category = RoadType.Road; Distance = 13.92; Location = "From East Bethesda to Pennsy Drive in Landover Hills" }
let roadI5    = { RoadName = "I 5";    Category = RoadType.Interstate; Distance = 796.432; Location = "From  Mexico-United States border to South of Oregon" }
let roadNE14  = { RoadName = "NE 14";  Category = RoadType.StateHighway; Distance = 203.54; Location = "From Superior, KS to SD 37" }
let roadI296  = { RoadName = "I 296";  Category = RoadType.Interstate; Distance = 3.43; Location = "Michigan" }
let roadUS2   = { RoadName = "US 2";   Category = RoadType.Road; Distance = 2571.00; Location = "Western Segment From Washington Rte 529 to I 75 in Michigan; Eastern Segment From US 11 in NY to I-95 in Maine." }

let roads = [| roadMD410; roadI5; roadNE14; roadI296; roadUS2 |]

A better alternative is to create each object directly in the array. After creating the array, you can access the members of the record using the period operator. Here is an example:

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

type RoadType =
    | Court
    | Street
    | Road
    | Avenue
    | Boulevard
    | StateRoad
    | StateHighway
    | Interstate
    | Unknown
    
type RoadSystem = {
    RoadName : string
    Category : RoadType
    Distance : float
    Location : string }
        
let roads = [| { RoadName = "MD 410"; Category = RoadType.Road; Distance = 13.92; Location = "From East Bethesda to Pennsy Drive in Landover Hills" };
               { RoadName = "I 5";    Category = RoadType.Interstate; Distance = 796.432; Location = "From  Mexico-United States border to South of Oregon" };
               { RoadName = "NE 14";  Category = RoadType.StateHighway; Distance = 203.54; Location = "From Superior, KS to SD 37" };
               { RoadName = "I 296";  Category = RoadType.Interstate; Distance = 3.43; Location = "Michigan" };
               { RoadName = "US 2";   Category = RoadType.Road; Distance = 2571.00; Location = "Western Segment From Washington Rte 529 to I 75 in Michigan; Eastern Segment From US 11 in NY to I-95 in Maine." } |]

let roadDatabase : Form = new Form(MaximizeBox = false, Text = "Road Database System", ClientSize = new System.Drawing.Size(637, 120), StartPosition = FormStartPosition.CenterScreen)

let lvwRoads : ListView = new ListView(GridLines = true, View = View.Details, FullRowSelect = true, Location = new Point(12, 12), Size = new System.Drawing.Size(611, 94))

let mutable col = lvwRoads.Columns.Add("Road Name", 75)
col <- lvwRoads.Columns.Add("Road Type", 80)
col <- lvwRoads.Columns.Add("Distance", 85, HorizontalAlignment.Right)
col <- lvwRoads.Columns.Add("Location", 365)

for road in roads do
    let lviRoad = new ListViewItem(sprintf "%s" road.RoadName)
    lviRoad.SubItems.Add(sprintf "%A" road.Category) |> ignore
    lviRoad.SubItems.Add(sprintf "%0.03f Miles" road.Distance) |> ignore
    lviRoad.SubItems.Add(sprintf "%s" road.Location) |> ignore
    lvwRoads.Items.Add lviRoad |> ignore

roadDatabase.Controls.Add lvwRoads

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

This would produce:

An Array of Records

An Array as a Label of a Record

A label of a record can be an array. When creating the member, specify its type followed by the array keyword. Here is an example:

type RoadSystem = {
    RoadName : string
    Distance : float
    Location : string
    Intersections : string array }

In the same way, you can create as many array members as you want. When creating an object, specify the value of the member as an array. Here is an example:

let road = {
    RoadName = "MD 410";
    Category = Road; Distance = 13.92;
    Location = "From East Bethesda to Pennsy Drive in Landover Hills";
    Intersections = [| "MD 355"; "MD 187"; "US 29"; "US 1"; "MD 295"; "US 50" |] }

Outside the object, you can access the label of the record and use it as you see fit. For example, you can display the array member using %A in the placeholder of the printf() or the printfn() function. On the other hand, you can access each item of the array using a for loop. Here is an example:

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

type RoadType =
    | Court
    | Street
    | Road
    | Avenue
    | Boulevard
    | StateRoad
    | StateHighway
    | Interstate
    | Unknown
    
type RoadSystem = {
    RoadName : string
    Category : RoadType
    Distance : float
    Location : string
    Intersections : string array }

let roads = [| { RoadName = "MD 410"; Category = Road; Distance = 13.92; Location = "From East Bethesda to Pennsy Drive in Landover Hills"; Intersections = [| "MD 355"; "MD 187"; "US 29"; "US 1"; "MD 295"; "US 50" |] }
               { RoadName = "I-81"; Category = Interstate; Distance = 855.00; Location = "From Dandridge, TN to Wellesley Island, NY/Hill Island, ON"; Intersections = [| "I-40"; "I-77"; "I-64"; "I-66"; "I-70"; "I-76"; "I-83"; "I-78"; "I-80"; "I-476"; "I-84"; "I-90"; "Highway 137" |] }
               { RoadName = "US 75"; Category = Road; Distance = 1239.00; Location = "From Dallas, TX to Moorhead, MN"; Intersections = [| "I-94"; "I-90"; "I-29"; "I-80"; "I-70/US-40/K-4"; "I-470/I335"; "I-35/US 50"; "I-44"; "I-40"; "I-635"; "I-30/I-45" |] }
               { RoadName = "I-96"; Category = Interstate; Distance = 3.43; Location = "Michigan, covering the following counties: Muskegon, Ottawa, Kent, Ionia, Clinton, Eaton, Ingham, Livingston, Oakland, and Wayne"; Intersections = [| "US 31"; "US 131"; "I-196"; "I-69"; "I-496/US 127"; "US 23"; "I-275/I-696/M-5"; "I-275/M-14"; "US 24"; "I-94"; "I-75" |] }
               { RoadName = "NE 14"; Category = RoadType.StateHighway; Distance = 203.54; Location = "From Superior, KS to SD 37 in Niobrara, NE"; Intersections = [| "K-14"; "US 6"; "I-80"; "US 30"; "US 275"; "US 20"; "N-12"; "SD 37" |] } |]


let roadDatabase : Form = new Form(MaximizeBox = false, Text = "Road Database System", ClientSize = new System.Drawing.Size(637, 340), StartPosition = FormStartPosition.CenterScreen)

let lvwRoads : ListView = new ListView(GridLines = true, View = View.Details, FullRowSelect = true, Location = new Point(12, 12), Size = new System.Drawing.Size(611, 94))

let mutable col = lvwRoads.Columns.Add("Road Name", 75)
col <- lvwRoads.Columns.Add("Road Type", 80)
col <- lvwRoads.Columns.Add("Distance", 80, HorizontalAlignment.Right)
col <- lvwRoads.Columns.Add("Location", 370)

for road in roads do
    let lviRoad = new ListViewItem(sprintf "%s" road.RoadName)
    lviRoad.SubItems.Add(sprintf "%A" road.Category) |> ignore
    lviRoad.SubItems.Add(sprintf "%0.02f Miles" road.Distance) |> ignore
    lviRoad.SubItems.Add(sprintf "%s" road.Location) |> ignore
    lvwRoads.Items.Add lviRoad |> ignore
roadDatabase.Controls.Add lvwRoads

let lbxIntersections : ListBox = new ListBox(Location = new Point(240, 120), Size = new Size(150, 200))
roadDatabase.Controls.Add lbxIntersections

let lvwRoadsSelectedIndexChanged(e : ListViewItemSelectionChangedEventArgs) =
    let roadSelected = e.Item.SubItems.Item(0).Text
    let mutable roadExists = false
    let mutable roadIdentifed = { RoadName = ""; Category =  RoadType.Unknown; Distance = 0.00; Location = ""; Intersections =[||] }

    lbxIntersections.Items.Clear()

    for road in roads do
        if road.RoadName = roadSelected then
            roadIdentifed <- road
            roadExists <- true

    if roadExists = true then
        lbxIntersections.Items.Add "Intersects With" |> ignore
        for intersection in roadIdentifed.Intersections do
            lbxIntersections.Items.Add(sprintf "%s" intersection) |> ignore
    else
        lbxIntersections.Items.Clear()

lvwRoads.ItemSelectionChanged.Add lvwRoadsSelectedIndexChanged

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

Here are examples of testing the program:

An Array as a Member of a Record

An Array as a Member of a Record

An Array as a Member of a Record

Arrays and Tuples

 

An Array of Tuples

The values of an array can be a tuple each. From our introduction to tuples, we know that the values of a tuple don't have to be of the same type. When creating the values of the array, make sure each is created as a tuple. Here is an example:

let paychekFrequencies = [| ("Weekly", 52);
			    ("Biweekly", 26);
			    ("Semimonthly", 24);
			    ("Monthly", 12) |]

Since this is primarily an array, you can use a for loop to access each tuple. Once you get to a tuple, you can retrieve its elements. Here is an example:

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

let paycheckCompany : Form = new Form(MaximizeBox = false,
                                      Text = "Paycheck Company",
                                      ClientSize = new System.Drawing.Size(187, 105),
                                      StartPosition = FormStartPosition.CenterScreen)

let lvwPayFrequencies : ListView = new ListView(GridLines = true,
                                                View = View.Details,
                                                FullRowSelect = true,
                                                Location = new Point(23, 12),
                                                Size = new System.Drawing.Size(141, 80))

let mutable colFrequency = lvwPayFrequencies.Columns.Add("Frequency", 75)
colFrequency <- lvwPayFrequencies.Columns.Add("Times", 60, HorizontalAlignment.Right)

let paychekFrequencies = [| ("Weekly", 52)
                            ("Biweekly", 26)
                            ("Semimonthly", 24)
                            ("Monthly", 12) |]

for frequency in paychekFrequencies do
    let (a, b) = frequency
    let lviFrequency = new ListViewItem(sprintf "%s" a)
    lviFrequency.SubItems.Add(sprintf "%i/Year" b) |> ignore
    lvwPayFrequencies.Items.Add lviFrequency |> ignore
paycheckCompany.Controls.Add lvwPayFrequencies

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

This would produce:

An Array of Tuples

The tuples in the array should (must) have the same number of elements each.

A Tuple of Arrays

The elements of a tuple can be made of arrays each. The arrays don't have to have the same size. Here is an example:

let geometry = ([| "Equilateral"; "Isosceles"; "Right" |],
                [| "Rectangle"; "Square"; "Parallelogram"; "Rhombus"; "Trapezoid" |],
                [| "Circle"; "Ellipse" |])

To get each individual array, you can declare a series of variables for each and assign the tuple to the series. From there, you can use each array. Here is an example:

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

let geometricShapes : Form = new Form(MaximizeBox = false,
                                      Text = "Geometric Shapes",
                                      ClientSize = new System.Drawing.Size(430, 110),
                                      StartPosition = FormStartPosition.CenterScreen)

let lbxShapes : ListBox = new ListBox(Location = new Point(12, 12),
                                      Size = new System.Drawing.Size(405, 82))

let geometry = ([| "Equilateral"; "Isosceles"; "Right" |],
                [| "Rectangle"; "Square"; "Parallelogram"; "Rhombus"; "Trapezoid" |],
                [| "Circle"; "Ellipse" |])

let (a, b, c) = geometry

lbxShapes.Items.Add "Geometric Shapes" |> ignore
lbxShapes.Items.Add "------------------------------------------------------------------------------------------------------------------------------------" |> ignore
lbxShapes.Items.Add(sprintf "Triangles:      %A" a) |> ignore
lbxShapes.Items.Add(sprintf "Quadrilaterals: %A" b) |> ignore
lbxShapes.Items.Add(sprintf "Circulars:      %A" c) |> ignore
geometricShapes.Controls.Add lbxShapes

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

This would produce:

A Tuple of Arrays

A Record Label as an Array of Tuples

As we know already, the values of a label of a record can consist of arrays. In the same way, a label of a record can be an array of tuples. To specify the type of the label include its data types in parentheses before the array keyword. Remember that the data types must be separated with *. Here is an example:

type RoadSystem = {
    RoadName : string
    Distance : float
    Location : string
    Intersections : (string * string) array }

When creating the values of the label, specify them as an array. Inside the [||] operator, each value must appear as a tuple. Here is an example:

type RoadSystem = {
    RoadName : string
    Distance : float
    Location : string
    Intersections : (string * string) array }

let NE14 = { RoadName = "NE 14";
             Category = RoadType.StateHighway;
             Distance = 203.54;
             Location = "From Superior, KS to SD 37 in Niobrara";
             Intersections = [| ("K-14", "Superior")
                                ("US 6", "Harvard")
                                ("I-80", "Aurora")
                                ("US 30", "Central City")
                                ("US 275", "Neligh")
                                ("US 20", "Brunswick")
                                ("N-12", "Niobrara") |] }

To access each item in the label, you can first the array as a whole from the label, then declare variables for each element of the tuple and ass the label to the variables. Here is an example:

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

type RoadType =
    | Court
    | Street
    | Road
    | Avenue
    | Boulevard
    | StateRoad
    | StateHighway
    | Interstate
    | Unknown
    
type RoadSystem = {
    RoadName : string
    Category : RoadType
    Distance : float
    Location : string
    Intersections : (string * string) array }

let roads = [| { RoadName = "MD 410"; Category = Road; Distance = 13.92; Location = "From East Bethesda to Pennsy Drive in Landover Hills"; Intersections = [| ("MD 355/MD 187", "Bethesda, MD"); ("US 29", "Silver Spring, MD"); ("US 1", "Riverdale Park, MD"); ("MD 295", "East Riverdale, MS"); ("US 50", "Landover Hills, MD") |] }
               { RoadName = "I-81";   Category = Interstate; Distance = 855.00; Location = "From Dandridge, TN to Wellesley Island, NY/Hill Island, ON"; Intersections = [| ("I-40", "Dandridge, TN"); ("I-77", "Wytheville, VA"); ("I-64", "Lexington, VA to Staunton, VA"); ("I-66", "Middletown, VA"); ("I-70", "Hagerstown, MD"); ("I-76", "Carlisle, PA"); ("I-83", "Harrisburg, PA"); ("I-78", "Union Township, PA"); ("I-80", "Hazleton, PA"); ("I-476", "Pittston, PA"); ("I-84", "Scranton, PA"); ("I-90", "Syracuse, NY"); ("Highway 137", " Wellesley Island, NY/Hill Island, ON") |] }
               { RoadName = "US 75";  Category = Road; Distance = 1239.00; Location = "From Dallas, TX to Moorhead, MN"; Intersections = [| ("I-30/I-45", "Dallas, TX"); ("I-635", "Dallas, TX"); ("I-40", "Henryetta, OK"); ("I-44", "Tulsa, OK"); ("I-35/US 50", "Lebo, KS"); ("I-470/I-335/Kansas Turnpike", "Topeka, KS"); ("I-70/US-40/K-4", "Topeka, KS"); ("I-80", "Omaha, NE"); ("I-29", "Sioux City, IA"); ("I-90", "Luverne, MN"); ("I-94", "Moorhead, MN"); ("PR 200", "Noyes, MN") |] }
               { RoadName = "I-96";   Category = Interstate; Distance = 3.43; Location = "Michigan, covering the following counties: Muskegon, Ottawa, Kent, Ionia, Clinton, Eaton, Ingham, Livingston, Oakland, and Wayne"; Intersections = [| ("US 31", "Norton Shores, MI"); ("US 131", "Walker, MI"); ("I-196", "Grand Rapids, MI"); ("I-69", "Lansing, MI"); ("I-496/US 127", "Lansing, MI"); ("US 23", "Brighton, MI"); ("I-275/I-696/M-5", "Farmington Hills, MI"); ("I-275/M-14", "Livonia, MI"); ("US 24", "Redford, MI"); ("I-94", "Detroit, MI"); ("I-75", "Detroit, MI") |] }
               { RoadName = "NE 14";  Category = RoadType.StateHighway; Distance = 203.54; Location = "From Superior, KS to SD 37 in Niobrara, NE"; Intersections = [| ("K-14", "Superior, NE"); ("US 6", "Harvard, NE"); ("I-80", "Aurora, NE"); ("US 30", "Central City, NE"); ("US 275", "Neligh, NE"); ("US 20", "Brunswick, NE"); ("N-12", "Niobrara, NE") |] } |]


let roadDatabase = new Form(StartPosition = FormStartPosition.CenterScreen,
			    ClientSize = new System.Drawing.Size(637, 340),
			    MaximizeBox = false, Text = "Road Database System")

let lvwRoads = new ListView(GridLines = true, View = View.Details,
			    Size = new System.Drawing.Size(611, 94),
			    FullRowSelect = true, Location = new Point(12, 12))

let mutable colRoads = lvwRoads.Columns.Add("Road Name", 75)
colRoads <- lvwRoads.Columns.Add("Road Type", 80)
colRoads <- lvwRoads.Columns.Add("Distance", 80, HorizontalAlignment.Right)
colRoads <- lvwRoads.Columns.Add("Location", 370)

for road in roads do
    let lviRoad = new ListViewItem(sprintf "%s" road.RoadName)
    lviRoad.SubItems.Add(sprintf "%A" road.Category) |> ignore
    lviRoad.SubItems.Add(sprintf "%0.02f Miles" road.Distance) |> ignore
    lviRoad.SubItems.Add(sprintf "%s" road.Location) |> ignore
    lvwRoads.Items.Add lviRoad |> ignore
roadDatabase.Controls.Add lvwRoads

let lvwIntersections = new ListView(View = View.Details,
				    Location = new Point(105, 120),
				    FullRowSelect = true, GridLines = true,
				    Size = new System.Drawing.Size(415, 200))

let mutable colIntersections = lvwIntersections.Columns.Add("Road", 55)
colIntersections <- lvwIntersections.Columns.Add("Intersects With", 140)
colIntersections <- lvwIntersections.Columns.Add("At/Near", 200)

roadDatabase.Controls.Add lvwIntersections

let lvwRoadsSelectedIndexChanged(e : ListViewItemSelectionChangedEventArgs) =
    let roadSelected = e.Item.SubItems.Item(0).Text
    let mutable roadExists = false
    let mutable roadIdentifed = { RoadName = ""; Category =  RoadType.Unknown; Distance = 0.00; Location = ""; Intersections =[||] }

    lvwIntersections.Items.Clear()

    for road in roads do
        if road.RoadName = roadSelected then
            roadIdentifed <- road
            roadExists <- true

    if roadExists = true then
        for intersection in roadIdentifed.Intersections do
            let (a, b) = intersection
            
            let lviIntersection = new ListViewItem(sprintf "%s" roadSelected)
            lviIntersection.SubItems.Add(sprintf "%s" a) |> ignore
            lviIntersection.SubItems.Add(sprintf "%s" b) |> ignore
            lvwIntersections.Items.Add lviIntersection |> ignore
    else
        lvwIntersections.Items.Clear()

lvwRoads.ItemSelectionChanged.Add lvwRoadsSelectedIndexChanged

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

Here are examples of testing the program:

A Label as an Array of Tuples

A Label as an Array of Tuples

A Label as an Array of Tuples

Arrays and Classes

 

An Array of Objects

The members of an array can be of any type, including objects of a class or structure. When it comes to classes (or structures), you have many options. You can use an existing class or you can create your own class. You can then create an array of objects of your chosen class. As done with records, you can declare variables for objects and put those objects in an array. A better alternative is to create each object in its placeholder in the array. To access a member of the array, you can use a for loop. Then, from the name of the looping identifier, use the period operator to access a member of the class. Here are examples:

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

type LoanType =
    | Personal
    | Vehicle
    | MusicalInstrument
    | Furniture
    
type Customer(acntNbr, name, category, principal, rate, months) =
    let nbr = ref acntNbr
    let nm  = ref name
    let cat = ref category
    let pv  = ref principal
    let rt  = ref rate
    let per = ref months

    member this.AccountNumber with get() = !nbr and set(value) = nbr := value
    member this.CustomerName  with get() = !nm  and set(value) = nm  := value
    member this.TypeOfLoan    with get() = !cat and set(value) = cat := value
    member this.PresentValue  with get() = !pv  and set(value) = pv  := value
    member this.InterestRate  with get() = !rt  and set(value) = rt  := value
    member this.Periods       with get() = !per and set(value) = per := value

    member this.InterestEarned with get() = principal * (rate / 100.00) * (months / 12.00)
    member this.FutureValue with get() = principal + this.InterestEarned
    member this.MonthlyPayment with get() = this.FutureValue / months

let loans = [| new Customer(827303, "Annie Ward", Personal, 7500.00, 14.50, 24.00)
               new Customer(638491, "Phillippe Kramer", Vehicle, 32890.00, 6.95, 60.00)
               new Customer(936477, "Leonard Thompson", Personal, 800.00, 12.00, 18.00)
               new Customer(997394, "Bernadette Wayne", MusicalInstrument, 1450.00, 12.75, 36.00)
               new Customer(182928, "Robert Hawthorne", Furniture, 7545.00, 18.25, 48.00)
               new Customer(200648, "Jennifer Raney", Personal, 2750.00, 10.50, 28.00) |]

let wattsALoan : Form = new Form(MaximizeBox = false, Text = "Watts A Loan - Loan Application System - Loans Records", ClientSize = new System.Drawing.Size(687, 130), StartPosition = FormStartPosition.CenterScreen)

let lvwLoansRecords : ListView = new ListView(GridLines = true, View = View.Details, FullRowSelect = true, Location = new Point(12, 12), Size = new System.Drawing.Size(661, 107))

let mutable colLoan = lvwLoansRecords.Columns.Add("Account #", 70)
colLoan <- lvwLoansRecords.Columns.Add("Customer Name", 105)
colLoan <- lvwLoansRecords.Columns.Add("Type", 80)
colLoan <- lvwLoansRecords.Columns.Add("Principal", 60, HorizontalAlignment.Right)
colLoan <- lvwLoansRecords.Columns.Add("Int Rate", 50, HorizontalAlignment.Right)
colLoan <- lvwLoansRecords.Columns.Add("Periods", 65, HorizontalAlignment.Right)
colLoan <- lvwLoansRecords.Columns.Add("Payment", 80, HorizontalAlignment.Right)
colLoan <- lvwLoansRecords.Columns.Add("Int Earned", 70, HorizontalAlignment.Right)
colLoan <- lvwLoansRecords.Columns.Add("Future Value", 75, HorizontalAlignment.Right)

for loan in loans do
    let lviLoan = new ListViewItem(sprintf "%i" loan.AccountNumber)
    lviLoan.SubItems.Add(sprintf "%s" loan.CustomerName) |> ignore
    lviLoan.SubItems.Add(sprintf "%A" loan.TypeOfLoan) |> ignore
    lviLoan.SubItems.Add(sprintf "%0.02f" loan.PresentValue) |> ignore
    lviLoan.SubItems.Add(sprintf "%0.02f%c" loan.InterestRate '%') |> ignore
    lviLoan.SubItems.Add(sprintf "%0.0f Months" loan.Periods) |> ignore
    lviLoan.SubItems.Add(sprintf "%0.02f/Month" loan.MonthlyPayment) |> ignore
    lviLoan.SubItems.Add(sprintf "%0.02f" loan.InterestEarned) |> ignore
    lviLoan.SubItems.Add(sprintf "%0.02f" loan.FutureValue) |> ignore
    lvwLoansRecords.Items.Add lviLoan |> ignore
wattsALoan.Controls.Add lvwLoansRecords

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

This would produce:

An Array of Objects

Arrays and Properties of a Class

We already know how to pass an array as parameter. This means that an array can be passed to the constructor of a class. When creating the constructor, it is a good idea to indicate that the parameter is an array. Here is an example:

type MachineUsageDepreciation(cost, salvage, life, usage : int array) = ...

In the body of the class, you can then use the parameter like a normal array. On the other hand, a property of a class can be an array. In fact, you can create a read-only property that would only produce an array that clients of the class can use. Here is an example:

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

let temporary : int array = [| 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0 |]

type MachineUsageDepreciation(cost, salvage, life, usage : int array) =
    member this.HourlyDepreciation with get() = (cost - salvage) / life
    member this.YearlyDepreciation with get() = [| for nbr in usage do yield float nbr * this.HourlyDepreciation |]
    new(cost, salvage, life) = MachineUsageDepreciation(cost, salvage, life, [||])

let unitsOfProduction : Form = new Form(MaximizeBox = false, Text = "Depreciation: Units of Production", ClientSize = new System.Drawing.Size(325, 355), StartPosition = FormStartPosition.CenterScreen)

unitsOfProduction.Controls.Add(new Label(Location = new Point(21, 25), AutoSize = true, Text = "Machine Cost:"))
let txtMachineCost : TextBox = new TextBox(Location = new Point(130, 22), Text = "0.00", TextAlign = HorizontalAlignment.Right, Width = 75)
unitsOfProduction.Controls.Add txtMachineCost

unitsOfProduction.Controls.Add(new Label(Location = new Point(21, 54), AutoSize = true, Text = "Salvage Value:"))
let txtSalvageValue : TextBox = new TextBox(Location = new Point(130, 51), Text = "0.00", TextAlign = HorizontalAlignment.Right, Width = 75)
unitsOfProduction.Controls.Add txtSalvageValue

unitsOfProduction.Controls.Add(new Label(Location = new Point(21, 83), AutoSize = true, Text = "Estimated Life:"))
let txtEstimatedLife : TextBox = new TextBox(Location = new Point(130, 80), Text = "0.00", TextAlign = HorizontalAlignment.Right, Width = 52)
unitsOfProduction.Controls.Add txtEstimatedLife
unitsOfProduction.Controls.Add(new Label(Location = new Point(187, 83), AutoSize = true, Text = "Hours"))

let lblLine = new Label(Location = new Point(21, 105), AutoSize = true)
lblLine.Text <- "Yearly Operations ________________________________"
unitsOfProduction.Controls.Add lblLine

unitsOfProduction.Controls.Add(new Label(Location = new Point(21, 135), AutoSize = true, Text = "Year:"))
let txtYearlyHours : TextBox = new TextBox(Location = new Point(130, 132), Text = "0.00", TextAlign = HorizontalAlignment.Right, Width = 52)
unitsOfProduction.Controls.Add txtYearlyHours
unitsOfProduction.Controls.Add(new Label(Location = new Point(187, 135), AutoSize = true, Text = "Hours/Year"))

unitsOfProduction.Controls.Add(new Label(Location = new Point(21, 83), AutoSize = true, Text = "Estimated Life:"))

unitsOfProduction.Controls.Add(new Label(Location = new Point(21, 209), AutoSize = true, Text = "Hourly Depreciation:"))
let txtHourlyDepreciation : TextBox = new TextBox(Location = new Point(130, 206), Text = "0.00", TextAlign = HorizontalAlignment.Right, Width = 52)
unitsOfProduction.Controls.Add txtHourlyDepreciation
unitsOfProduction.Controls.Add(new Label(Location = new Point(187, 209), AutoSize = true, Text = "/Hour"))

unitsOfProduction.Controls.Add(new Label(Location = new Point(21, 242), AutoSize = false, Size = new System.Drawing.Size(70, 32), Text = "Depreciation Schedule:"))
let lbxDepreciationSchedule : ListBox = new ListBox(Location = new Point(130, 239), Size = new System.Drawing.Size(120, 95))
unitsOfProduction.Controls.Add lbxDepreciationSchedule

let btnAdd : Button = new Button(Location = new Point(255, 130), Width = 50, Text = "Add")
let btnAddClick e =
    if   temporary.[0] = 0 then temporary.[0] <- int txtYearlyHours.Text
    elif temporary.[1] = 0 then temporary.[1] <- int txtYearlyHours.Text
    elif temporary.[2] = 0 then temporary.[2] <- int txtYearlyHours.Text
    elif temporary.[3] = 0 then temporary.[3] <- int txtYearlyHours.Text
    elif temporary.[4] = 0 then temporary.[4] <- int txtYearlyHours.Text
    elif temporary.[5] = 0 then temporary.[5] <- int txtYearlyHours.Text
    elif temporary.[6] = 0 then temporary.[6] <- int txtYearlyHours.Text
    elif temporary.[7] = 0 then temporary.[7] <- int txtYearlyHours.Text
    elif temporary.[8] = 0 then temporary.[8] <- int txtYearlyHours.Text
    elif temporary.[9] = 0 then temporary.[9] <- int txtYearlyHours.Text

    txtYearlyHours.Text <- "0.00"
    txtYearlyHours.Focus() |> ignore

btnAdd.Click.Add btnAddClick
unitsOfProduction.Controls.Add btnAdd

let btnCalculate : Button = new Button(Location = new Point(24, 163), Size = new System.Drawing.Size(280, 31), Text = "Calculate")
let btnCalculateClick e =
    let machineCost   = float txtMachineCost.Text
    let salvageValue  = float txtSalvageValue.Text
    let estimatedLife = float txtEstimatedLife.Text
    
    let dimension = ref 0
    
    for a in temporary do
        if a <> 0 then dimension := !dimension + 1

    let timesUsed = [| for i in 0 .. !dimension - 1 -> i |]

    for b in 0 .. !dimension - 1 do
        timesUsed.[b] <- temporary.[b]

    let depreciation = new MachineUsageDepreciation(machineCost, salvageValue, estimatedLife, timesUsed)
    txtHourlyDepreciation.Text <- sprintf "%0.03f" depreciation.HourlyDepreciation

    lbxDepreciationSchedule.Items.Clear()
    for yearly in depreciation.YearlyDepreciation do
        lbxDepreciationSchedule.Items.Add yearly |> ignore

btnCalculate.Click.Add btnCalculateClick
unitsOfProduction.Controls.Add btnCalculate

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

Here is an example of testing the program:

Arrays and Properties of a Class

Otherwise, you can create a read-write property that gets its value as array from the outside and makes its array value available to the outside world. Here is an example:

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

let temporary : int array = [| 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0 |]

type MachineUsageDepreciation(cost, salvage, life, usage : int array) =
    let mutable hrs : int array = usage

    member this.HourlyDepreciation with get() = (cost - salvage) / life
    member this.Operations with get() = hrs and set(hours) = hrs <- hours
    member this.YearlyDepreciation with get() = [| for nbr in hrs do yield float nbr * this.HourlyDepreciation |]

    new(cost, salvage, life) = MachineUsageDepreciation(cost, salvage, life, [||])

let unitsOfProduction : Form = new Form(MaximizeBox = false, Text = "Depreciation: Units of Production", ClientSize = new System.Drawing.Size(325, 370), StartPosition = FormStartPosition.CenterScreen)

unitsOfProduction.Controls.Add(new Label(Location = new Point(21, 25), AutoSize = true, Text = "Machine Cost:"))
let txtMachineCost : TextBox = new TextBox(Location = new Point(130, 22), Text = "0.00", TextAlign = HorizontalAlignment.Right, Width = 75)
unitsOfProduction.Controls.Add txtMachineCost

unitsOfProduction.Controls.Add(new Label(Location = new Point(21, 54), AutoSize = true, Text = "Salvage Value:"))
let txtSalvageValue : TextBox = new TextBox(Location = new Point(130, 51), Text = "0.00", TextAlign = HorizontalAlignment.Right, Width = 75)
unitsOfProduction.Controls.Add txtSalvageValue

unitsOfProduction.Controls.Add(new Label(Location = new Point(21, 83), AutoSize = true, Text = "Estimated Life:"))
let txtEstimatedLife : TextBox = new TextBox(Location = new Point(130, 80), Text = "0.00", TextAlign = HorizontalAlignment.Right, Width = 52)
unitsOfProduction.Controls.Add txtEstimatedLife
unitsOfProduction.Controls.Add(new Label(Location = new Point(187, 83), AutoSize = true, Text = "Hours"))

let lblLine = new Label(Location = new Point(21, 105), AutoSize = true)
lblLine.Text <- "Yearly Operations ________________________________"
unitsOfProduction.Controls.Add lblLine

unitsOfProduction.Controls.Add(new Label(Location = new Point(21, 135), AutoSize = true, Text = "Year:"))
let txtYearlyHours : TextBox = new TextBox(Location = new Point(130, 132), Text = "0.00", TextAlign = HorizontalAlignment.Right, Width = 52)
unitsOfProduction.Controls.Add txtYearlyHours
unitsOfProduction.Controls.Add(new Label(Location = new Point(187, 135), AutoSize = true, Text = "Hours/Year"))

unitsOfProduction.Controls.Add(new Label(Location = new Point(21, 83), AutoSize = true, Text = "Estimated Life:"))

unitsOfProduction.Controls.Add(new Label(Location = new Point(21, 209), AutoSize = true, Text = "Hourly Depreciation:"))
let txtHourlyDepreciation : TextBox = new TextBox(Location = new Point(130, 206), Text = "0.00", TextAlign = HorizontalAlignment.Right, Width = 52)
unitsOfProduction.Controls.Add txtHourlyDepreciation
unitsOfProduction.Controls.Add(new Label(Location = new Point(187, 209), AutoSize = true, Text = "/Hour"))

unitsOfProduction.Controls.Add(new Label(Location = new Point(52, 240), AutoSize = true, Text = "Usage:"))
unitsOfProduction.Controls.Add(new Label(Location = new Point(155, 240), AutoSize = true, Text = "Depreciation Schedule:"))

let lbxUsage : ListBox = new ListBox(Location = new Point(50, 258), Size = new System.Drawing.Size(100, 95))
unitsOfProduction.Controls.Add lbxUsage
let lbxDepreciationSchedule : ListBox = new ListBox(Location = new Point(155, 258), Size = new System.Drawing.Size(120, 95))
unitsOfProduction.Controls.Add lbxDepreciationSchedule

let btnAdd : Button = new Button(Location = new Point(255, 130), Width = 50, Text = "Add")
let btnAddClick e =
    if   temporary.[0] = 0 then temporary.[0] <- int txtYearlyHours.Text
    elif temporary.[1] = 0 then temporary.[1] <- int txtYearlyHours.Text
    elif temporary.[2] = 0 then temporary.[2] <- int txtYearlyHours.Text
    elif temporary.[3] = 0 then temporary.[3] <- int txtYearlyHours.Text
    elif temporary.[4] = 0 then temporary.[4] <- int txtYearlyHours.Text
    elif temporary.[5] = 0 then temporary.[5] <- int txtYearlyHours.Text
    elif temporary.[6] = 0 then temporary.[6] <- int txtYearlyHours.Text
    elif temporary.[7] = 0 then temporary.[7] <- int txtYearlyHours.Text
    elif temporary.[8] = 0 then temporary.[8] <- int txtYearlyHours.Text
    elif temporary.[9] = 0 then temporary.[9] <- int txtYearlyHours.Text

    txtYearlyHours.Text <- "0.00"
    txtYearlyHours.Focus() |> ignore

btnAdd.Click.Add btnAddClick
unitsOfProduction.Controls.Add btnAdd

let btnCalculate : Button = new Button(Location = new Point(24, 163), Size = new System.Drawing.Size(280, 31), Text = "Calculate")
let btnCalculateClick e =
    let machineCost   = float txtMachineCost.Text
    let salvageValue  = float txtSalvageValue.Text
    let estimatedLife = float txtEstimatedLife.Text
    
    let dimension = ref 0
    
    for a in temporary do
        if a <> 0 then dimension := !dimension + 1

    let timesUsed = [| for i in 0 .. !dimension - 1 -> i |]

    for b in 0 .. !dimension - 1 do
        timesUsed.[b] <- temporary.[b]

    let depreciation = new MachineUsageDepreciation(machineCost, salvageValue, estimatedLife, timesUsed)
    txtHourlyDepreciation.Text <- sprintf "%0.03f" depreciation.HourlyDepreciation

    lbxUsage.Items.Clear()
    lbxDepreciationSchedule.Items.Clear()

    for usage in depreciation.Operations do
        lbxUsage.Items.Add(sprintf "%i Hours/Year" usage) |> ignore

    for yearly in depreciation.YearlyDepreciation do
        lbxDepreciationSchedule.Items.Add(sprintf "$%0.0f" yearly) |> ignore

btnCalculate.Click.Add btnCalculateClick
unitsOfProduction.Controls.Add btnCalculate

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

Here is an example of testing the program:

Arrays and Properties of a Class

In the same way, you can create a property that works with or produces an array of objects or an array or tuples. Here is an example:

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

let temporary : int array = [| 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0 |]

type MachineUsageDepreciation(cost, salvage, life, usage : int array) =
    let mutable hrs : int array = usage
    let mutable counter = 0

    member this.HourlyDepreciation with get() = (cost - salvage) / life
    member this.Operations with get() = hrs and set(hours) = hrs <- hours
    member this.YearlyDepreciation with get() = [| for nbr in hrs do yield float nbr * this.HourlyDepreciation |]
    member this.DepreciationSchedule with get() =
                                        [| for n in hrs do yield (float n, float n * this.HourlyDepreciation) |]

    new(cost, salvage, life) = MachineUsageDepreciation(cost, salvage, life, [||])

let unitsOfProduction : Form = new Form(MaximizeBox = false, Text = "Depreciation: Units of Production", ClientSize = new System.Drawing.Size(325, 370), StartPosition = FormStartPosition.CenterScreen)

unitsOfProduction.Controls.Add(new Label(Location = new Point(21, 25), AutoSize = true, Text = "Machine Cost:"))
let txtMachineCost : TextBox = new TextBox(Location = new Point(130, 22), Text = "0.00", TextAlign = HorizontalAlignment.Right, Width = 75)
unitsOfProduction.Controls.Add txtMachineCost

unitsOfProduction.Controls.Add(new Label(Location = new Point(21, 54), AutoSize = true, Text = "Salvage Value:"))
let txtSalvageValue : TextBox = new TextBox(Location = new Point(130, 51), Text = "0.00", TextAlign = HorizontalAlignment.Right, Width = 75)
unitsOfProduction.Controls.Add txtSalvageValue

unitsOfProduction.Controls.Add(new Label(Location = new Point(21, 83), AutoSize = true, Text = "Estimated Life:"))
let txtEstimatedLife : TextBox = new TextBox(Location = new Point(130, 80), Text = "0.00", TextAlign = HorizontalAlignment.Right, Width = 52)
unitsOfProduction.Controls.Add txtEstimatedLife
unitsOfProduction.Controls.Add(new Label(Location = new Point(187, 83), AutoSize = true, Text = "Hours"))

let lblLine = new Label(Location = new Point(21, 105), AutoSize = true)
lblLine.Text <- "Yearly Operations ________________________________"
unitsOfProduction.Controls.Add lblLine

unitsOfProduction.Controls.Add(new Label(Location = new Point(21, 135), AutoSize = true, Text = "Year:"))
let txtYearlyHours : TextBox = new TextBox(Location = new Point(130, 132), Text = "0.00", TextAlign = HorizontalAlignment.Right, Width = 52)
unitsOfProduction.Controls.Add txtYearlyHours
unitsOfProduction.Controls.Add(new Label(Location = new Point(187, 135), AutoSize = true, Text = "Hours/Year"))

unitsOfProduction.Controls.Add(new Label(Location = new Point(21, 83), AutoSize = true, Text = "Estimated Life:"))

unitsOfProduction.Controls.Add(new Label(Location = new Point(21, 209), AutoSize = true, Text = "Hourly Depreciation:"))
let txtHourlyDepreciation : TextBox = new TextBox(Location = new Point(130, 206), Text = "0.00", TextAlign = HorizontalAlignment.Right, Width = 52)
unitsOfProduction.Controls.Add txtHourlyDepreciation
unitsOfProduction.Controls.Add(new Label(Location = new Point(187, 209), AutoSize = true, Text = "/Hour"))

unitsOfProduction.Controls.Add(new Label(Location = new Point(55, 240), AutoSize = true, Text = "Depreciation Schedule:"))

let lvwDepreciationSchedule : ListView = new ListView(Location = new Point(50, 258), Size = new System.Drawing.Size(225, 95), GridLines = true, View = View.Details, FullRowSelect = true)
lvwDepreciationSchedule.Columns.Add("Year", 40) |> ignore
lvwDepreciationSchedule.Columns.Add("Usage", 95, HorizontalAlignment.Center) |> ignore
lvwDepreciationSchedule.Columns.Add("Depreciation", 85, HorizontalAlignment.Right) |> ignore

unitsOfProduction.Controls.Add lvwDepreciationSchedule

let btnAdd : Button = new Button(Location = new Point(255, 130), Width = 50, Text = "Add")
let btnAddClick e =
    if   temporary.[0] = 0 then temporary.[0] <- int txtYearlyHours.Text
    elif temporary.[1] = 0 then temporary.[1] <- int txtYearlyHours.Text
    elif temporary.[2] = 0 then temporary.[2] <- int txtYearlyHours.Text
    elif temporary.[3] = 0 then temporary.[3] <- int txtYearlyHours.Text
    elif temporary.[4] = 0 then temporary.[4] <- int txtYearlyHours.Text
    elif temporary.[5] = 0 then temporary.[5] <- int txtYearlyHours.Text
    elif temporary.[6] = 0 then temporary.[6] <- int txtYearlyHours.Text
    elif temporary.[7] = 0 then temporary.[7] <- int txtYearlyHours.Text
    elif temporary.[8] = 0 then temporary.[8] <- int txtYearlyHours.Text
    elif temporary.[9] = 0 then temporary.[9] <- int txtYearlyHours.Text

    txtYearlyHours.Text <- "0.00"
    txtYearlyHours.Focus() |> ignore

btnAdd.Click.Add btnAddClick
unitsOfProduction.Controls.Add btnAdd

let btnCalculate : Button = new Button(Location = new Point(24, 163), Size = new System.Drawing.Size(280, 31), Text = "Calculate")
let btnCalculateClick e =
    let machineCost   = float txtMachineCost.Text
    let salvageValue  = float txtSalvageValue.Text
    let estimatedLife = float txtEstimatedLife.Text
    
    let dimension = ref 0
    
    for a in temporary do
        if a <> 0 then dimension := !dimension + 1

    let timesUsed = [| for i in 0 .. !dimension - 1 -> i |]

    for b in 0 .. !dimension - 1 do
        timesUsed.[b] <- temporary.[b]

    let depreciation = new MachineUsageDepreciation(machineCost, salvageValue, estimatedLife, timesUsed)
    txtHourlyDepreciation.Text <- sprintf "%0.03f" depreciation.HourlyDepreciation

    lvwDepreciationSchedule.Items.Clear()

    let mutable year = 1
    for usage in depreciation.DepreciationSchedule do
        let (hour, depreciation) = usage

        let lviDepreciation = new ListViewItem(sprintf "%i" year)
        lviDepreciation.SubItems.Add(sprintf "%0.0f Hours/Year" hour) |> ignore
        lviDepreciation.SubItems.Add(sprintf "$%0.0f" depreciation) |> ignore
        lvwDepreciationSchedule.Items.Add lviDepreciation |> ignore
        year <- year + 1
btnCalculate.Click.Add btnCalculateClick
unitsOfProduction.Controls.Add btnCalculate

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

Here is an example of testing the program:

A List as a Property A List as a Property
A List as a Property A List as a Property
A List as a Property A List as a Property
A List as a Property

Normally, when creating a read-write property that would use an array, you can simply create a regular property. Here is an example:

type PayrollPreparation(number, times) =
    let mutable nbr = number;
    let mutable tms = times;
    member this.EmployeeeNumber with get() = nbr and set(value) = nbr <- value;
    member this.TimesWorked with get() = tms and set(value) = tms <- value;

When you specify the value of the property, you provide the array. Once this is done, when using the property outside the class, treat it as an array. Here is an example:

type Employee = {
    EmployeeNumber : string
    FirstName      : string
    LastName       : string
    HourlySalary   : double }

let employees = [| { EmployeeNumber = "8022-3840"; FirstName = "Mark";  LastName = "Plant";  HourlySalary = 24.55 };
                   { EmployeeNumber = "5840-2497"; FirstName = "Carol"; LastName = "Mylans"; HourlySalary = 16.25 };
                   { EmployeeNumber = "2081-7008"; FirstName = "Maria"; LastName = "Pappas"; HourlySalary = 22.75 }; |]

type PayrollPreparation(number, times) =
    let mutable nbr = number
    let mutable tms = times
    member this.EmployeeeNumber with get() = nbr and set(value) = nbr <- value
    member this.TimesWorked with get() = tms and set(value) = tms <- value
    member this.CalculateTotalTime() =
        let mutable sum = 0.00
        for t in tms do sum <- sum + t
        sum
    member this.CalculateWeeklySalary() =
        let mutable salary = 0.00
        for empl in employees do
            if empl.EmployeeNumber = nbr then salary <- empl.HourlySalary
        this.CalculateTotalTime() * salary

let pp = PayrollPreparation("5840-2497", [| 6.0; 7.5; 8.0; 6.5; 7.5; 0.0; 0.0 |])

Arrays and Methods of a Class

Like a regular function in a module, a method of a class can use an array in many ways. For example, a method can receive an array as parameter. We saw this for a constructor. A method can also return an array. When accessing the method outside the class, remember that it returns an array. This means that you can apply the operations of arrays on the call to that method. Here is an example:

type Employee = {
    EmployeeNumber : string
    FirstName      : string
    LastName       : string
    HourlySalary   : double }

let employees = [| { EmployeeNumber = "8022-3840"; FirstName = "Mark";  LastName = "Plant";  HourlySalary = 24.55 };
                   { EmployeeNumber = "5840-2497"; FirstName = "Carol"; LastName = "Mylans"; HourlySalary = 16.25 };
                   { EmployeeNumber = "2081-7008"; FirstName = "Maria"; LastName = "Pappas"; HourlySalary = 22.75 }; |]

type PayrollPreparation(number, times) =
    let mutable nbr = number;
    let mutable tms = times;
    member this.EmployeeeNumber with get() = nbr and set(value) = nbr <- value;
    member this.TimesWorked with get() = tms and set(value) = tms <- value;
    member this.PaySummary(hourlySalary) : float array =
        let mutable regularTime = 0.00
        let mutable overtime = 0.00
        let mutable regularAmount = 0.00
        let mutable overtimeSalary = 0.00
        let mutable totalWeekTime = 0.00
        let mutable overtimeAmount = 0.00
        
        for t in tms do totalWeekTime <- totalWeekTime + t
        overtimeSalary <- hourlySalary * 1.5

        // If the employee worked under 40 hours, there is no overtime
        if totalWeekTime < 40. then
            regularTime <- totalWeekTime
            regularAmount <- hourlySalary * regularTime
            //overtime <- 0.00
            //overtimeAmount <- 0.00
        // If the employee worked over 40 hours, calculate the overtime
        elif totalWeekTime >= 40. then
            regularTime <- 40.
            regularAmount <- hourlySalary * 40.
            overtime <- totalWeekTime - 40.
            overtimeAmount <- overtime * overtimeSalary
        [| regularTime; overtime; regularAmount; overtimeAmount; regularAmount + overtimeAmount |]

let pp = PayrollPreparation("5840-2497", [| 6.0; 7.5; 8.0; 6.5; 7.5; 0.0; 0.0 |])

Notice that the method could have been written as follows (it may be long to read but it produces the same result):

type PayrollPreparation(number, times) =
    let mutable nbr = number;
    let mutable tms = times;
    member this.EmployeeeNumber with get() = nbr and set(value) = nbr <- value;
    member this.TimesWorked with get() = tms and set(value) = tms <- value;
    member this.PaySummary(hourlySalary) : float array =
        let mutable totalWeekTime = 0.00
                  
        for t in tms do totalWeekTime <- totalWeekTime + t
                                                                                            
        // If the employee worked under 40 hours, there is no overtime
        if totalWeekTime < 40. then
            [| totalWeekTime; 0.00; hourlySalary * totalWeekTime; 0.00; hourlySalary * totalWeekTime |]
        else // if totalWeekTime >= 40. then
            [| 40.00; totalWeekTime - 40.00; hourlySalary * 40.00; (totalWeekTime - 40.00) * (hourlySalary * 1.50); hourlySalary * 40.00 + ((totalWeekTime - 40.00) * (hourlySalary * 1.50)) |]

Characteristics of Arrays

 

Introduction

The F# language provides many mechanisms to perform various types of operations. Besides the regular core operations of the language, the language's own library is equipped with a namespace named Microsoft.FSharp.Collections in which exists in a module named Array.

An Empty Array

In some cases, if you are not ready to specify the values when creating the array, you can create it empty. To do this, specify the value of the array as [||]. Here is an example:

let timesWorked = [||]

As an alternative, to let you create an empty array, the Array module provides a function named empty. Its signature is:

Array.empty<'T> :  'T []

Here is an example of using it:

let timesWorked = Array.empty

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

Array.isEmpty : 'T [] -> bool

The Length of an Array

The length of an array is the number of items it contains. To let you get this information, the Array module is equipped with a property named Length.

As an alternative, the Array module is equipped with a function named length. The function takes one argument as the array whose number of items must be found.

Techniques of Creating Arrays

 

Creating an Array

We know that there are various techniques to create an array, and when creating an array, you should provide the original values of the array. One way to do this is to initialize the array with the values of your choice. To support this, the Array class is equipped with a method named create. Its signature is:

Array.create : int -> 'T -> 'T []

This method takes two arguments. The first is the number of items the array will need. The second argument is the default value for each item.

Creating an Array With Zero Values

If you create an empty array, it remains empty and you cannot add values to it. That's why, when creating an array, you should provide the desired values. If you don't have those values, you can still create an array, specify its number of items, but specify each item as 0. To support this operation, the Array module is equipped with a method named zeroCreate. Its signature is:

Array.zeroCreate : int -> 'T []

This method takes one argument as the number of items in the array. Each item receives a value of 0. Here is an example of calling it:

let customers : Customer array = Array.zeroCreate 5

Initialyzing an Array

 

Introduction

After creating the array, you can specify the values of its members or you can change them. This can be done by accessing an item using the period operator and assigning a value using the -> operator. Here are exampes:

let times : float array = Array.zeroCreate 7

times.[0] <- 8.00
times.[1] <- 8.50
times.[2] <- 6.00
times.[3] <- 9.00
times.[4] <- 7.50
times.[5] <- 9.00
times.[6] <- 7.50

If the members of the array are objects, you can access each item by its index and assign an object-value to it. Here are examples:

type Customer = {
    AccountNumber : string
    FirstName     : string
    LastName      : string }

let customers : Customer array = Array.zeroCreate 5

customers.[0] <- { AccountNumber = "807495"; FirstName = "Julius"; LastName = "Gluck" }
customers.[1] <- { AccountNumber = "928037"; FirstName = "Stephanie"; LastName = "Dugan" }
customers.[2] <- { AccountNumber = "279714"; FirstName = "William"; LastName = "Bamberg" }
customers.[3] <- { AccountNumber = "680513"; FirstName = "Kelly"; LastName = "Stewart" }
customers.[4] <- { AccountNumber = "479242"; FirstName = "Mark"; LastName = "Goddard" }

Copying a Fraction of an Array

You can get the fraction of an array and copy that fraction into another array. This operation can be carried by the blit() method of the Array class. Its signature is:

Array.blit : 'T [] -> int -> 'T [] -> int -> int -> unit

This method takes five arguments. The first argument is the array that holds the original value. It is called the source array. The third argument is the array that will receive the fraction. This is called the target array. The target can contain some or all values. This means that some values could have default or unnecessary values. The second argument is the starting index from which to copy values from the source array. The fourth argument is the starting index where to start adding the values that were copied from the source. The last (fifth) argument is the number of items to copy from the source, of course starting from the index specified by the second argument. Here is an example:

Copying an Array

If you have a good array you want to use in a particular scenario without messing with the original array, you can make a copy. This can be done through the copy() method of the Array class. Its signature is:

Array.copy : 'T [] -> 'T []

This method takes one argument as the array that holds the values.

Iterating Through an Array

   

Getting an Item Based on its Index

We already know that you can use a for loop to visiat each member of an array. As an alternative, to let you access an item based on its index, the Array class provides a method named get. Its signature is:

Array.get : 'T [] -> int -> 'T

This method takes two arguments. The first is the array that holds the values. The second argument is the index of the item you want.

Conditional Arrays

 

The Existense of an Item in an Array

To let you find out whether an item exists in an array, the Array module provides a function named exists. Its signature is:

Array.exists : ('T -> bool) -> 'T list -> bool

This is a Boolean function that takes two arguments. The first is a statement that will scan the whole array to test the condition by which a member of the array exists. If a member responds to the conditional existence, the function returns true. If no member of the array responds to that condition, the function concludes that there is no member that responds and the function returns false.

Mapping an Array

Mapping consists of creating a new array based on items from an existing array to which you will perform an operation on each item. To let you do this,  the Array module is equipped with a function named map. Its signature is:

Array.map : ('T -> 'U) -> 'T [] -> 'U []

This function takes two arguments. The first is a function. If the array is made of objects, the function can consist of simply selecting a property or calling a method from the class. The second argument is the array that holds the values. Here is an example of calling it:

type RoadType =
    | Court
    | Street
    | Road
    | Avenue
    | Boulevard
    | StateHighway
    | Interstate
    | Unknown
    
type RoadSystem = {
    RoadName : string
    Category : RoadType
    Distance : float
    Location : string
    Intersections : string array }

let roads = [| { RoadName = "MD 410"; Category = RoadType.Road; Distance = 13.92; Location = "From East Bethesda to Pennsy Drive in Landover Hills"; Intersections = [| "MD 355"; "MD 187"; "Maple Ave"; "MD 185"; "Colesville Rd" |] }
               { RoadName = "I 5"; Category = RoadType.Interstate; Distance = 796.432; Location = "From  Mexico–United States border to South of Oregon"; Intersections = [| "SR 15"; "I 8"; "I-10"; "I-210"; "SR 99"; "I-580"; "I-80"; |] }
               { RoadName = "NE 14"; Category = RoadType.StateHighway; Distance = 203.54; Location = "From Superior, KS to SD 37"; Intersections = [| "NE 8"; "US 136"; "NE 74"; ""; "NE 41"; "US 6"; "I 80"; "US 34"; "NE 66"; "US 30"; "NE 92"; "NE 22" |] }
               { RoadName = "I 296"; Category = RoadType.Interstate; Distance = 3.43; Location = "Michigan"; Intersections = [||] }
               { RoadName = "US 2"; Category = RoadType.Road; Distance = 2571.00; Location = "Western Segment From Washington Rte 529 to I 75 in Michigan; Eastern Segment From US 11 in NY to I-95 in Maine."; Intersections = [| "US 395"; "I 15"; "US 87"; "US 83"; "I 29" |] } |]

// Selecing on the RoadName property of the class
let roadsNames = Array.map (function (road : RoadSystem) -> road.RoadName) roads

Another way to map an array of objects is to find out whether the values of members respond to a certain condition. In the following example, we apply a condition when calling the Array.map() method to find out whether a road is an Interstate:

type RoadType =
    | Court
    | Street
    | Road
    | Avenue
    | Boulevard
    | StateHighway
    | Interstate
    | Unknown
    
type RoadSystem = {
    RoadName : string
    Category : RoadType
    Distance : float
    Location : string
    Intersections : string array }

let roads = [| { RoadName = "MD 410"; Category = RoadType.Road; Distance = 13.92; Location = "From East Bethesda to Pennsy Drive in Landover Hills"; Intersections = [| "MD 355"; "MD 187"; "Maple Ave"; "MD 185"; "Colesville Rd" |] }
               { RoadName = "I 5"; Category = RoadType.Interstate; Distance = 796.432; Location = "From  Mexico–United States border to South of Oregon"; Intersections = [| "SR 15"; "I 8"; "I-10"; "I-210"; "SR 99"; "I-580"; "I-80"; |] }
               { RoadName = "NE 14"; Category = RoadType.StateHighway; Distance = 203.54; Location = "From Superior, KS to SD 37"; Intersections = [| "NE 8"; "US 136"; "NE 74"; ""; "NE 41"; "US 6"; "I 80"; "US 34"; "NE 66"; "US 30"; "NE 92"; "NE 22" |] }
               { RoadName = "I 296"; Category = RoadType.Interstate; Distance = 3.43; Location = "Michigan"; Intersections = [||] }
               { RoadName = "US 2"; Category = RoadType.Road; Distance = 2571.00; Location = "Western Segment From Washington Rte 529 to I 75 in Michigan; Eastern Segment From US 11 in NY to I-95 in Maine."; Intersections = [| "US 395"; "I 15"; "US 87"; "US 83"; "I 29" |] } |]

let roadsNames = Array.map (function (road : RoadSystem) -> road.Category = RoadType.Interstate) roads

Arrays and Built-In Classes

 

Ranges in Built-In Collection-Based Classes

In Lesson 4, we introduced collections as a way to use a list of items. In reality, we introduced the arrays without specifying that name. In that same lesson, we saw that most collection-based controls have a property named Items that itself is a collection. The collection that leads that property is equipped with a method named AddRange. That method actually expects an array as argument. This allows you to create an array of values (primitive types or objects of classes) as argument.

Arrays and Strings

The String provides many types of support for strings. To start, to create and initialize a string, you can pass an array of characters to it. To support this, the class is equipped with the following constructor:

new : 
    value : char[] -> String

Here is an example:

open System
open System.Windows.Forms

let firstName = String([| 'A'; 'n'; 'd'; 'y' |])

MessageBox.Show(firstName, "String", MessageBoxButtons.OK, MessageBoxIcon.Information) |> ignore

This would produce:

Arrays and Strings

Once (and because) a string is considered a collection of items, you can use the for operator to access each member of the collection.

We were introduced to string concatenation in Lesson when we found out that you can add two, three, or four strings together. The String class is more flexible than that. It allows you to add as many strings as you want. This can be done by passing an array of strings to the Concat() method. In this case, the signature to use is:

static member Concat : 
    values:string[] -> string

To let you format a string with great flexibility, the String is equipped with the following signature to the Format() method:

static member Format : 
    format:string * 
    args:Object[] -> string

This method takes two arguments. The first is a string that contains the sentence and the formats you want to use. Each format uses a placeholder made of {} that includes an incrementing number. The second argument is an array or values that will fill the placeholders in the first argument.

   
   
 

Home Copyright © 2012-2015, FunctionX Home