Fundamentals of Lists

Overview of Lists

A list is a group of constant values of the same type. The list if immutable, meaning that once the list is created, it cannot change. Although this is the standard definition, we will still all types of operations you can perform on a list.

Introduction to Creating a List

To create a list, start with an opening square bracket "[" and end with a closing square bracket "]". Inside the brackets, create the members of the list. Each member ends with a semicolon. Here are examples:

// A list of numbers
[ 12; 22; 48; 115; 306; ]
// A list of characters
[ 'c'; 'd'; 'g'; 'j'; 'm'; ]
// A list of strings, names
[ "Frank"; "James"; "Joshua"; "Mary"; ]

The semicolon on the last member is optional. On the other hand, you don't have to create all members on the same line. In fact, you can write the square brackets on their own lines and the members on a separate line after the opening square bracket. Here is an example:

[
"Frank"; "James"; "Joshua"; "Mary";
]

Although you don't have to indent, indentation makes the list easier to read:

[
    "Frank"; "James"; "Joshua"; "Mary";
]

Another alternative is to have each member of the list on its own line. Here is an example:

[
    "Frank";
    "James";
    "Joshua";
    "Mary";
];

If you decide to create each member on its own line, you can omit the semicolons. Here are examples:

[
    "Frank"
    "James"
    "Joshua"
    "Mary"
];

An Empty List

A list is referred to as empty if it doesn't contain any item, but it is still considered a list. To create an empty list, type the square brackets but leave them empty. Here is an example:

[]

A list is a kind of variable. Although you can use it without naming it, if you plan to refer to it in different parts of your code, you should give it a name. To do this, declare a variable using the let keyword, followed by a name for the variable, and assign the list to it. Here is an example:

let numbers = [ 12; 22; 48; 115; 306 ]

Remember that the items can be separated from the square brackets by different lines:

let characters = [
    'c'; 'd'; 'g'; 'j'; 'm'
];

To store an empty list in a variable, assign empty square brackets to it. Here is an example:

let numbers = []

Creating a Simple Range

A list is a series of arranged items. If you want some items that are known in advance and they are consecutive, you can specify only the beginning and end of the series. When creating the list, in the square brackets, type the starting item, followed by .., and followed by the ending item. It is a good idea to put a space before and after .. to make it easier to read. Here are examples:

// A range of numbers
[ 2 .. 8 ];
// A range of letters
[ 'h' .. 'q' ];

Creating a Range For a Loop

Instead of creating a range from known constant values, the F# language proposes a keyword named for. It allows you to indicate only the begining and ending values. The basic formula is:

[ for variable-name in range -> body ]

The variable-name can be any lowercase letter or any name. The range is usually specified as start-value .. end-value. The body of the loop is created after the -> sign. It can simply consist of the variable-name . Here is an example:

[ for variable in 1 .. 8 -> variable ]

This is equivalent to numbers from 1 to 8:

[1; 2; 3; 4; 5; 6; 7; 8]

Yielding an Item From a Loop

An alternative to use the -> operator is to use the do yield expression. Here is an example:

[ for variable in 1 .. 8 do yield variable ]

A Skip Range

When you create a range, you specify the starting and the ending values. When the range is processed, the compiler will add 1 to the first value to get the second value. Then it would add 1 to each subsequent value to get the next value, until that next value is immediately less than or equal to the ending value. Instead of adding 1 to each value to get the next, you may want to use another incrementing scheme. That type of range is created using the skip range operator representd by .. ..

The formula to create a skip range is:

Start .. Step .. End

The algorithm works as follows:

Here is an example:

[ 3 .. 2 .. 20 ]

In this case, the range would start at 3. The value 2 would be added to the first, 3, to get the next. Then 2 would be added to the new value, and so on, until the new number is immediately lower than the last number specified in the range:

Numbers: [ 3; 5; 7; 9; 11; 13; 15; 17; 20 ]

As a consequence, the End value is included in the result if it gets out of range when the step is added to the previous value.

Looping a List

For Looping to an End

Looping consists of going through a series of values from a starting point to an ending point. The formula to follow is:

for identifier = start [ to | downto ] end do
   body

The for, the to, and the do keywords are required. The downto keyword can be used in place of the do keyword in some cases as we will see. The identifier is a name used to specify a local variable that will hold the current value as the series is being scanned. start represents the value by which to start counting and end is the value by which to stop. The body of the looping operation starts with the do keyword but is written on the next line. That body can contain any code you see fit. Here is an example that displays some numbers being counted:

for i = 1 to 5 do
    printfn "Number: %d" i

This would produce:

Number: 1
Number: 2
Number: 3
Number: 4
Number: 5
Press any key to close this window . . .

The start and end values can also come from previously declared variables.

For Looping in a Range

It is possible to loop in a range of values. The formula to follow is:

for identifier in range do
   body

In this case, the range can consist of a starting and an ending values separated by two periods. Here is an example:

for i in 1 .. 5 do
    printfn "Number: %d" i;

This would produce the same result as above.

Looping While a Value Exists

Instead of counting from a starting value to a known end, you may want to execute a statement from a begining value but continue as long as a certain condition exists. This is done using the while keyword. The formula to follow is:

while Condition do
    body

The while and the do keywords are required. The Condition is something that needs to be checked. It could be a conditional operation or anything that can produce a true or false result. After the do keyword, create a body for the loop. Here is an example:

let mutable a = 1;

while a < 6 do
    printfn "Number: %d" a;
    a <- a + 1;

Creating Items From an Expression

Most of the time, you will create a looping range because you want the numbers to follow a certain pattern instead of simply incrementing. Here is an example:

[ for variable in 0 .. 15 -> variable * 5 ]

Although each member of a list must be a constant value, each value can be created from an expression. Here is an example:

[ for variable in 0 .. 15 do yield variable * 5 ]

Using a List

Introduction

To present a list of items, you can call the printf() or the printfn() function and use %A as the placeholder. If you had previously declared a variable for a list and had initialized it, you can specify its name as the placeholder of the printf() or the printfn() function. Here is an example:

let names = [ "Frank"; "James"; "Joshua"; "Mary" ];
printfn "%A" names;

This would produce:

["Frank"; "James"; "Joshua"; "Mary"]
Press any key to close this window . . .

Instead for first declaring the variable, we saw that you can create a name-less list. In this case, you can provide that list directly in the placeholder. Here is an example:

printfn "%A" [ "Frank"; "James"; "Joshua"; "Mary" ];

You can also write the items on different lines. Here is an example:

printfn "%A" [
    "Frank"
    "James"
    "Joshua"
    "Mary"
];

This would produce:

["Frank"; "James"; "Joshua"; "Mary"]
Press any key to close this window . . .

Either way, this means that you don't have to first declare a variable for a list. You can just create the list directly where it is needed.

In the same way, you can use %A to show the values created from a range. Here is an example:

let range = [3 .. 12 ]
 
printfn "Numbers: %A" range;

This would produce:

Numbers: [3; 4; 5; 6; 7; 8; 9; 10; 11; 12]
 
Press any key to close this window . . .

You use the same technique for a skip-range. Here is an example:

let skipRange = [3 .. 2 .. 20 ]
 
printfn "Numbers: %A" skipRange;

This would produce:

Numbers: [3; 5; 7; 9; 11; 13; 15; 17; 19]
 
Press any key to close this window . . .

For Each Item in a List

To help you visit each member of a list, the F# language provides looping operation that uses the for keyword. The formula to follow is:

for identifier / pattern in list do
   body

The for, the in, and the do keywords are required. The identifier could be a variable name that will hold the value to be retrieved from the list. Here is an example:

for i in [ "Frank"; "James"; "Joshua"; "Mary" ] do
    printfn "Name: %s" i;

This would produce:

Name: Frank
Name: James
Name: Joshua
Name: Mary
Press any key to close this window . . .

As Long As (while) it is not the End of the List

Besides (or instead of) a for loop, you can use the while operator to visit each member of the list. As done for the for operator, if you decide (or want, or have) to use while, make sure you specify where and how to start the visit and where and how to end it. You can first declare an integer variable and assign it the desired starting value. In the body of the while statement, visit each member of the list. If you are using an integer variable, you can increment it each time to move to the next value. Here is an example:

let mutable i = 0

let names = [ "Frank"; "James"; "Joshua"; "Mary" ]
while i < names.Length  do
    printfn "Name: %s" names.[i]
    i <- i + 1

A List in a List

In the lists we have created so far, we treated each item as a primitive type. In reality, each member of the list is considered a complete type and could be anything, including its own list.

To make a list a member of another list, in the placeholder of the list, create the list just as we have done so far, using its own square brackets. If you decide to use this technique, all list items must be the same type of list but they can have different numbers of items. Here is an example:

let names = [ ["Joshua"; "Morrison"]; ["Frank"; "Aaron"; "Xaviera"]; ["James"; "Lalong"] ];
printfn "%A" names;

To make the code easier to read, you can type the individual lists on their own lines. Here is an example:

let names =
    [
	[ "Joshua"; "Morrison" ];
	[ "Frank"; "Aaron"; "Xaviera" ];
	[ "James"; "Lalong" ]
    ]

Operations on a List

Introduction

In the F# language, lists are represented by a module named List. The module is defined in the Microsoft.FSharp.Collections namespace (https://github.com/dotnet/fsharp/blob/main/src/FSharp.Core/list.fs). To provide some characteristics to a list, the Microsoft.FSharp.Collections namespace provides a generic union named List. This union is quipped with two constructors (operators) and various propertites.

An Empty List

We saw that, to create an empty list, you can assign empty square brackets [] to it. Alternatively, to let you create an empty list, the List module is equipped with a function named empty:

[<CompiledName("Empty")>]
    let empty<'T> = ([]: 'T list)

Here is an example of calling it and getting its value:

let noTenant = List.empty;
 
printfn "Tenants: %A" noTenant

After creating a list and while using it, at any time, to let you find out whether the list has no item, the List union is equipped with a Boolean property named IsEmpty:

[<CompiledName("IsEmpty")>]
    let isEmpty list =
        match list with
        | [] -> true
        | _ -> false

The Number of Items in a List

The number of items in a list is referred to as its length. To support it, the List union contains a property named Length. Its equivalent in the List module is the length() function. Its signature is:

List.length : 'T list -> int

As you can see, this function takes a list as argument and it returns an integer as the number of items in the list.

Getting an Item Based on Its Index

The items of a list are stored in a zero-based series. The first item occupies the 0 position. The second item occupies the 1 position, and so on. To let you get to an item based on its position+1 in the list, the List union is equipped with an indexed property named Item. Here is an example of using the property:

let numbers = [ 3 .. 2 .. 20 ]
printfn "Numbers: %A\n" numbers
 
let sixth = numbers.Item(5)
printfn "6th Member: %d\n" sixth

This would produce:

Numbers: [3; 5; 7; 9; 11; 13; 15; 17; 19]
 
6th Member: 13
 
Press any key to close this window . . .

In the same way, you can access any member of the list based on its position. Make sure you provide an index that is less than or equal to the number of items - 1. If you provide a number beyond the number of items, you will get an error.

Introductory Operations on Lists

Checking Whether a List is Empty

We know that, to create an empty list, you can assign empty square brackets [] to it. Here is an example:

let numbers = []
 
printfn "Numbers: %A" numbers

This would produce:

Numbers: []
Press any key to close this window . . .

To let you find out whether a list is empty, you can use the match operator with an option as []. If that option is valid, it means that the list is empty. The other option can be an underscore, which means that the list contains at least one item. Here are examples:

let numbers = []
let names = [ "Frank"; "James"; "Joshua"; "Mary" ]
 
match numbers with
| [] -> printfn "The list is empty"
| _ -> printfn "Numbers: %A" numbers
 
match names with
| [] -> printfn "There is no name in the list"
| _ -> printfn "Name: %A" names

This would produce:

The list is empty
Name: ["Frank"; "James"; "Joshua"; "Mary"]
Press any key to close this window . . .

Attaching an Item to a List

As mentioned already, a list is immutable. Base on that, you can add (a) new item(s) to the list but you would get a new, different list, that contains the original item(s) and the new one(s). To let you perform this operation, the List union is equipped with, or defines, an operator as ::. To use it, start with the let operator and a new name, assign the new value to it, followed by :: and the original list. Here is an example:

let names = [ "Frank"; "James"; "Joshua"; "Mary" ]

printfn "%A" names
 
let additional = "Gabriel" :: names
printfn "%A" additional

This would produce:

[ "Frank"; "James"; "Joshua"; "Mary" ]
[ "Gabriel"; "Frank"; "James"; "Joshua"; "Mary" ]
Press any key to close this window . . .

Keep in mind that the original list has not changed:

// Names
let names = [ "Frank"; "James"; "Joshua"; "Mary" ]
 
printfn "%A" names
 
let additional = "Gabriel" :: names
printfn "%A" additional
 
printfn "%A" names

This would produce:

[ "Frank"; "James"; "Joshua"; "Mary" ]
[ "Gabriel"; "Frank"; "James"; "Joshua"; "Mary" ]
["Frank"; "James"; "Joshua"; "Mary" ]
Press any key to close this window . . .

Concatenating Some Lists

Concatenating two list consists of adding them. To perform this operation, use the @ operator in place of +. The lists must be compatible. Here is an example:

let parents  = [ "Frank"; "James"; "Joshua"; "Maryy" ]
let students = [ "Hermine"; "Sebastien"; "Lestery" ]
 
printfn "Parents:  %A" parents
printfn "Students: %A" students
 
printfn "\nFamilies: %A"  (parents @ students);

This would produce:

Parents:  ["Frank"; "James"; "Joshua"; "Mary"]
Students: ["Hermine"; "Sebastien"; "Lester"]
 
Families: ["Frank"; "James"; "Joshua"; "Mary"; "Hermine"; "Sebastien"; "Lester"]
 
Press any key to close this window . . .

If you plan to use the result many times, you can store it in a variable. To do this, assign the concatenation to the variable. Here is an example:

let parents  = [ "Frank"; "James"; "Joshua"; "Maryy" ]
let students = [ "Hermine"; "Sebastien"; "Lestery" ]
let families = parents @ students
 
printfn "Parents:  %A" parents
printfn "Students: %A" students
 
printfn "Families: %A" families;

As an alternative to the @ operator, the List module provides a function named append. Its signature is

List.append : 'T list -> 'T list -> 'T list

This function takes two arguments that each is a list. The function returns a list. Here is an example of calling it:

type EmploymentStatus =
    | Unknown  = 0
    | FullTime = 1
    | PartTime = 2
    | Intern   = 3
    | Seasonal = 4
     
type Employee(emplNbr, status, salary) =
    member this.EmployeeNumber = emplNbr
    member this.EmploymentStatus : EmploymentStatus = status
    abstract member WeeklyTime : unit -> double
    default this.WeeklyTime() = 40.00
    abstract member WeeklySalary : unit -> double
    default this.WeeklySalary() = salary
 
let fullTimeEmployeesPayrolls = [ Employee("9749-8075", EmploymentStatus.FullTime, 60000.00); Employee("2038-4051", EmploymentStatus.FullTime, 82000.00);
                                  Employee("5031-9259", EmploymentStatus.FullTime, 55000.00); Employee("7092-3094", EmploymentStatus.FullTime, 104000.00);
                                  Employee("2903-0481", EmploymentStatus.FullTime, 88500.00); Employee("5020-4681", EmploymentStatus.FullTime, 65200.00); ]
let otherEmployeesPayrolls    = [ Employee("9270-8039", EmploymentStatus.PartTime, 15800.00); Employee("2807-4083", EmploymentStatus.Seasonal, 22400.00);
                                  Employee("2405-8296", EmploymentStatus.Seasonal, 35400.00); Employee("2813-3044", EmploymentStatus.PartTime, 32500.00) ]
                                  
let payrollSummary = List.append fullTimeEmployeesPayrolls otherEmployeesPayrolls
 
printfn "Fixed Salaried Employee Payroll"
printfn "==================================="
printfn "           Weekly \tYearly"
printfn "Empl #      Time\tSalary"
printfn "-----------------------------------"
for payroll in payrollSummary do
    printfn "%s  %A\t%0.0f" payroll.EmployeeNumber payroll.EmploymentStatus (payroll.WeeklySalary())
printfn "===================================\n"

This would produce:

Fixed Salaried Employee Payroll
===================================
           Weekly       Yearly
Empl #      Time        Salary
-----------------------------------
9749-8075  FullTime     60000
2038-4051  FullTime     82000
5031-9259  FullTime     55000
7092-3094  FullTime     104000
2903-0481  FullTime     88500
5020-4681  FullTime     65200
9270-8039  PartTime     15800
2807-4083  Seasonal     22400
2405-8296  Seasonal     35400
2813-3044  PartTime     32500
===================================
 
Press any key to close this window . . .

Lists and Functions

Creating Items From a Function

Although each member of a list must be a constant value, each value can be created from a function. In the square brackets, call the function every time you need a value. If the function takes (a) parameter(s), make sure you pass the appropriate and necesary argument. Here is an example:

let multiply x = x * 2.27

let numbers = [ multiply 1.26; multiply 88.03; multiply 7.25; multiply 15.58 ]

for n in numbers do
    printfn "Number: %0.04f" n

This would produce:

Number: 2.8602
Number: 199.8281
Number: 16.4575
Number: 35.3666
Press any key to close this window . . .

As an option, you can precede each function call with the yield keyword. Here is an example:

let multiply x = x * 2.27

let numbers = [ yield multiply 1.26; yield multiply 88.03; yield multiply 7.25; yield multiply 15.58 ]

for n in numbers do
    printfn "Number: %0.04f" n

To add the values to the list, you can create a for loop that uses a range and calls the function to which you pass each value of the range. Here is an example:

let add x = x + x
let numbers = [ for variable in 1 .. 8 -> add variable ]

printfn "Numbers: %A" numbers

Remember that you can use do yield instead of ->. Here is an example:

let add x = x + x
let numbers = [ for variable in 1 .. 8 do yield add variable ]
 
printfn "Numbers: %A" numbers

This would produce:

Numbers: [2; 4; 6; 8; 10; 12; 14; 16]
Press any key to close this window . . .

Of course, you can have a more complicated function than that. You can also generate values from the method of a class.

Returning a List from a Function

You can create a function that returns a list. To do this, make sure the last assignment of the function is a list. Here is an example:

let specifyWeeklyTime() =
    [ 8.50; 9.50; 8.00; 10.00; 9.00; 0.00; 0.00]

In other words, when a function has finished its assignment, you can make sure its last statement is a list. Here is an example:

let specifyWeeklyTime() =
    let monday    =  8.50
    let tuesday   =  9.50
    let wednesday =  8.00
    let thursday  = 10.00
    let friday    =  9.00
    let saturday  =  0.00
    let sunday    =  0.00
    
    [ monday; tuesday; wednesday; thursday; friday; saturday; sunday; ]

In fact, a function can simply return a variable as long as that variable represents a list. Here is an example:

let specifyWeeklyTime() =
    let monday    =  8.50
    let tuesday   =  9.50
    let wednesday =  8.00
    let thursday  = 10.00
    let friday    =  9.00
    let saturday  =  0.00
    let sunday    =  0.00
    
    let times = [ monday; tuesday; wednesday; thursday; friday; saturday; sunday; ]
    times // The returned variable, a list

You can then use that returned value outside of the function. Here is an example:

let specifyWeeklyTime() =
    [ 8.50; 9.50; 8.00; 10.00; 9.00; 0.00; 0.00]
 
printfn "Weekly Time: %A" (specifyWeeklyTime())

You can also get the returned list and store it in a variable before using it. Here is an example:

let specifyWeeklyTime() =
    [ 8.50; 9.50; 8.00; 10.00; 9.00; 0.00; 0.00]
 
let times = specifyWeeklyTime()
printfn "Weekly Times: %A" times

This would produce:

Weekly Time: [8.5; 9.5; 8.0; 10.0; 9.0; 0.0; 0.0]
Press any key to close this window . . .

Once you have a variable that holds a list, you can access each member of that list. Here is an example:

let specifyWeeklyTime() =
    [ 8.50; 9.50; 8.00; 10.00; 9.00; 0.00; 0.00]
 
let times = specifyWeeklyTime()
 
for time in times do
    printfn "Time: %0.02f" time

This would produce:

Time: 8.50
Time: 9.50
Time: 8.00
Time: 10.00
Time: 9.00
Time: 0.00
Time: 0.00
Press any key to close this window . . .

Just like a function can return one list, it can return as many as you want. For example, you can create a function that returns a list of lists. Here is an example:

let specifyWeeklyTimes() =
    [ [ 8.50; 9.50; 8.00; 10.00; 9.00; 0.00; 0.00];
      [ 6.00; 8.00; 9.00;  7.00; 8.00; 0.00; 0.00]; ]
 
printfn "Weekly Time: %A\n" (specifyWeeklyTimes())
 
let times = specifyWeeklyTimes()
 
for week in times do
    for time in week do
        printfn "Time: %0.02f" time

In the same way, you can return as many lists as you want.

A List as Parameter

A function can receive a parameter that is a list and treat it accordingly. Because F# is an inferred language, you can just pass the name of a parameter without a data type, and then use the parameter in the function as if that parameter were a list. Here is an example:

let displayWeeklyTimes(listOfTimes) =
    printfn "Weekly Time: %A" listOfTimes

Normally, at this time, the compiler doesn't know what type of parameter this is, and that parameter could be anything. When calling the function, pass a list as argument and the compiler will apply the appropriate rules based on the type of argument you passed. Here are examples:

let specifyWeeklyTime() =
    [ 8.50; 9.50; 8.00; 10.00; 9.00; 0.00; 0.00];
 
let displayWeeklyTimes(listOfTimes) =
    printfn "Weekly Time: %A" listOfTimes
 
displayWeeklyTimes(specifyWeeklyTime())
printfn "--------------------------------------------------"

This would produce:

Weekly Time: [8.5; 9.5; 8.0; 10.0; 9.0; 0.0; 0.0]
--------------------------------------------------
Press any key to close this window . . .

As mentioned already, when creating a function that takes a list as parameter, you can just specify a name for the parameter. Since you know that the parameter is a list, in the body of the function, treat the argument as a list, using all approriate rules of lists. For example, you can use a loop on the parameter. Here is an example:

let specifyWeeklyTime() =
    [ 8.50; 9.50; 8.00; 10.00; 9.00; 0.00; 0.00];
 
let displayWeeklyTimes(listOfTimes) =
    printfn "Weekly Time: %A" listOfTimes
 
let times = specifyWeeklyTime()
 
let showWeeklyTimes(listOfTimes) =
    for time in listOfTimes do
        printfn "Time: %0.02f" time
 
displayWeeklyTimes(times)
printfn "--------------------------------------------------"
showWeeklyTimes(times)
printfn "--------------------------------------------------"

This would produce:

Weekly Time: [8.5; 9.5; 8.0; 10.0; 9.0; 0.0; 0.0]
--------------------------------------------------
Time: 8.50
Time: 9.50
Time: 8.00
Time: 10.00
Time: 9.00
Time: 0.00
Time: 0.00
--------------------------------------------------
Press any key to close this window . . .

In the same way, you can pass a parameter that is a list of lists (or a list of lists of lists...) and process it appropriately.

Lists and Tuples

Creating a Range From a Tuple

Lists are very important in functional programming. To enhance the functionalities of lists, the F# language provides various built-in operators and functions.

Tuples provide the ability to create a range from two members of a tuple:

When the .. operator is applied on both members, the result is a range that includes both values and the values between them. Here is an example:

let range(a, b) = 
    [a .. b];
 
let result = range(2, 8);
printfn "Values from a range: %A" result;

This would produce:

Values from a range: [2; 3; 4; 5; 6; 7; 8]
Press any key to close this window . . .

You can also provide non-readable characters. In this case, the compiler would try to find their range. Here is an example:

let range(a, b) = 
    [a .. b];
 
let result = range('$', '*');
printfn "Values from a range: %A" result;

This would produce:

Values from a range: ['$'; '%'; '&'; '\''; '('; ')'; '*']
Press any key to close this window . . .

Either way, if the compiler cannot find values between both members of the tuple, in which case it cannot create a range, the compiler would produce an empty range [].

Creating a Skip Range From a Tuple

A skip range is a technique of specifying the starting value of a range, the end value of a range, and the value to add to each value to get the next one. You can get such a skip-range from a tuple. Here is an example:

let range(a, b, c) = 
    [a .. b .. c];
 
let result = range(2, 3, 16);
printfn "Values from a skip-range: %A" result;

This would produce:

Values from a skip-range: [2; 5; 8; 11; 14]
Press any key to close this window . . .

A List of Tuples

You can create a list where each element is a tuple. Here is an example:

let timesWorked = [("Monday", 8.00); ("Tuesday", 9.00); ("Wednesday", 8.50); ("Thursday", 8.00); ("Friday", 8.50)]

You can then access the elements. For example, you can use %A to represent the list. Here is an example:

let timesWorked = [("Monday", 8.00); ("Tuesday", 9.00); ("Wednesday", 8.50); ("Thursday", 8.00); ("Friday", 8.50)]

printfn "Times Worked: %A" timesWorked

This would produce:

Times Worked: [("Monday", 8.0); ("Tuesday", 9.0); ("Wednesday", 8.5); ("Thursday", 8.0); ("Friday", 8.5)]
Press any key to close this window . . .

You can also use a for loop to access each tuple. Here is an example:

let timesWorked = [("Monday", 8.00); ("Tuesday", 9.00); ("Wednesday", 8.50); ("Thursday", 8.00); ("Friday", 8.50)]

for t in timesWorked do
    printfn "Time Worked: %A" t

This would produce:

Time Worked: ("Monday", 8.0)
Time Worked: ("Tuesday", 9.0)
Time Worked: ("Wednesday", 8.5)
Time Worked: ("Thursday", 8.0)
Time Worked: ("Friday", 8.5)
Press any key to close this window . . .

You can also use any technique of your choice to decompose the tuples and access their individual values. Here is an example:

let timesWorked = [("Monday", 8.00); ("Tuesday", 9.00); ("Wednesday", 8.50); ("Thursday", 8.00); ("Friday", 8.50)]

printfn "Time Worked"
printfn "-----------------"
for t in timesWorked do
    let a, b = t
    printfn "%s: %0.02f" a b
printfn "================="

This would produce:

Time Worked
-----------------
Monday: 8.00
Tuesday: 9.00
Wednesday: 8.50
Thursday: 8.00
Friday: 8.50
=================
Press any key to close this window . . .

A Tuple of Lists

You can have a tuple whose elements are lists each. Here is an example:

let timesWorked = ([8.00; 9.00; 8.50; 8.00; 8.50], [8.50; 9.50; 8.00; 10.00; 9.00])

printfn "Work for 2 weeks: %A" timesWorked

This would produce:

Work for 2 weeks: ([8.0; 9.0; 8.5; 8.0; 8.5], [8.5; 9.5; 8.0; 10.0; 9.0])
Press any key to close this window . . .

You can then decompose the tuple to get each list. Here is an example:

let timesWorked = ([8.00; 9.00; 8.50; 8.00; 8.50], [8.50; 9.50; 8.00; 10.00; 9.00])

let a, b = timesWorked
printfn "Work 1 time worked: %A" a
printfn "Work 2 time worked: %A" b

This would produce:

Work 1 time worked: [8.0; 9.0; 8.5; 8.0; 8.5]
Work 2 time worked: [8.5; 9.5; 8.0; 10.0; 9.0]
Press any key to close this window . . .

To access the individual elements of each list, you have various options. You can use a for loop to visit each element of the list. Here are examples:

let timesWorked = ([8.00; 9.00; 8.50; 8.00; 8.50], [8.50; 9.50; 8.00; 10.00; 9.00])

let (a, b) = timesWorked

printfn "Work 1 time worked"
for t in a do
    printfn "%0.02f" t

printfn "Work 2 time worked"
for t in b do
    printfn "%0.02f" t

This would produce:

Work 1 time worked
8.00
9.00
8.50
8.00
8.50
Work 2 time worked
8.50
9.50
8.00
10.00
9.00
Press any key to close this window . . .

You can also store each list in a (temporary) variable. Here are examples:

let timesWorked = ([8.00; 9.00; 8.50; 8.00; 8.50], [8.50; 9.50; 8.00; 10.00; 9.00])

let (a, b) = timesWorked

let week1 = [for t in a do yield t]
let week2 = [for t in b do yield t]

printfn "Work 1 time worked: %A" week1
printfn "Work 2 time worked: %A" week2

This would produce:

Work 1 time worked: [8.0; 9.0; 8.5; 8.0; 8.5]
Work 2 time worked: [8.5; 9.5; 8.0; 10.0; 9.0]
Press any key to close this window . . .

Once you have each list, you can use it using any of the techniques and features of an F# list.

A List of Records

The members of a list can come from a record. You can first define a record, create objects from it, and use them as members of a list. Here is an example:

type OccupancyStatus =
| Other       = 0
| Available   = 1
| Occupied    = 2
| NeedsRepair = 3
 
type Apartment = {
    UnitNumber      : string
    Bedrooms        : int
    Bathrooms       : float
    SecurityDeposit : int
    MonthlyRate     : int
    Status          : OccupancyStatus }
 
let a399475 = { UnitNumber = "101"; Bedrooms = 2; Bathrooms = 2.00; SecurityDeposit = 650; MonthlyRate = 1150; Status = OccupancyStatus.Available   }
let a508293 = { UnitNumber = "102"; Bedrooms = 1; Bathrooms = 1.00; SecurityDeposit = 500; MonthlyRate =  950; Status = OccupancyStatus.NeedsRepair }
let a729397 = { UnitNumber = "103"; Bedrooms = 1; Bathrooms = 1.00; SecurityDeposit = 500; MonthlyRate =  925; Status = OccupancyStatus.Available   }

Instead of first creating the objects, you can add them directly in the list. Here is an example:

let apartments = [
    { UnitNumber = "101"; Bedrooms = 2; Bathrooms = 2.00; SecurityDeposit = 650; MonthlyRate = 1150; Status = OccupancyStatus.Available   }
    { UnitNumber = "102"; Bedrooms = 1; Bathrooms = 1.00; SecurityDeposit = 500; MonthlyRate =  950; Status = OccupancyStatus.NeedsRepair }
    { UnitNumber = "103"; Bedrooms = 1; Bathrooms = 1.00; SecurityDeposit = 500; MonthlyRate =  925; Status = OccupancyStatus.Available   }
    { UnitNumber = "104"; Bedrooms = 3; Bathrooms = 2.00; SecurityDeposit = 850; MonthlyRate = 1350; Status = OccupancyStatus.Occupied    }
    { UnitNumber = "105"; Bedrooms = 2; Bathrooms = 1.00; SecurityDeposit = 550; MonthlyRate = 1150; Status = OccupancyStatus.Available   }
 ]

After doing this, you can access each member of the list as an individual record. Here is an example:

type OccupancyStatus =
| Other       = 0
| Available   = 1
| Occupied    = 2
| NeedsRepair = 3
 
type Apartment = {
    UnitNumber      : string
    Bedrooms        : int
    Bathrooms       : float
    SecurityDeposit : int
    MonthlyRate     : int
    Status          : OccupancyStatus }
 
let apartments = [
    { UnitNumber = "101"; Bedrooms = 2; Bathrooms = 2.00; SecurityDeposit = 650; MonthlyRate = 1150; Status = OccupancyStatus.Available   }
    { UnitNumber = "102"; Bedrooms = 1; Bathrooms = 1.00; SecurityDeposit = 500; MonthlyRate =  950; Status = OccupancyStatus.NeedsRepair }
    { UnitNumber = "103"; Bedrooms = 1; Bathrooms = 1.00; SecurityDeposit = 500; MonthlyRate =  925; Status = OccupancyStatus.Available   }
    { UnitNumber = "104"; Bedrooms = 3; Bathrooms = 2.00; SecurityDeposit = 850; MonthlyRate = 1350; Status = OccupancyStatus.Occupied    }
    { UnitNumber = "105"; Bedrooms = 2; Bathrooms = 1.00; SecurityDeposit = 550; MonthlyRate = 1150; Status = OccupancyStatus.Available   } ]
 
for apart in apartments do
    printfn "Apartment Record: %A" apart

This would produce:

Apartment Record: {UnitNumber = "102";
 Bedrooms = 1;
 Bathrooms = 1.0;
 SecurityDeposit = 500;
 MonthlyRate = 950;
 Status = NeedsRepair;}
Apartment Record: {UnitNumber = "103";
 Bedrooms = 1;
 Bathrooms = 1.0;
 SecurityDeposit = 500;
 MonthlyRate = 925;
 Status = Available;}
Apartment Record: {UnitNumber = "104";
 Bedrooms = 3;
 Bathrooms = 2.0;
 SecurityDeposit = 850;
 MonthlyRate = 1350;
 Status = Occupied;}
Apartment Record: {UnitNumber = "105";
 Bedrooms = 2;
 Bathrooms = 1.0;
 SecurityDeposit = 550;
 MonthlyRate = 1150;
 Status = Available;}
Press any key to close this window . . .

Or you can access each member of the record from the variable of the list. Here is an example:

type OccupancyStatus =
| Other       = 0
| Available   = 1
| Occupied    = 2
| NeedsRepair = 3
 
type Apartment = {
    UnitNumber      : string
    Bedrooms        : int
    Bathrooms       : float
    SecurityDeposit : int
    MonthlyRate     : int
    Status          : OccupancyStatus }
 
let apartments = [
    { UnitNumber = "101"; Bedrooms = 2; Bathrooms = 2.00; SecurityDeposit = 650; MonthlyRate = 1150; Status = OccupancyStatus.Available   }
    { UnitNumber = "102"; Bedrooms = 1; Bathrooms = 1.00; SecurityDeposit = 500; MonthlyRate =  950; Status = OccupancyStatus.NeedsRepair }
    { UnitNumber = "103"; Bedrooms = 1; Bathrooms = 1.00; SecurityDeposit = 500; MonthlyRate =  925; Status = OccupancyStatus.Available   }
    { UnitNumber = "104"; Bedrooms = 3; Bathrooms = 2.00; SecurityDeposit = 850; MonthlyRate = 1350; Status = OccupancyStatus.Occupied    }
    { UnitNumber = "105"; Bedrooms = 2; Bathrooms = 1.00; SecurityDeposit = 550; MonthlyRate = 1150; Status = OccupancyStatus.Available   } ]
 
printfn "====================================================="
printfn "\t\t\tMonthly"
printfn "Unit # Beds\tBaths\tRent\tDeposit Status"
printfn "-----------------------------------------------------"
for apart in apartments do
    printfn "%s\t%i\t%.2f\t%d\t%d\t%A" apart.UnitNumber apart.Bedrooms apart.Bathrooms apart.MonthlyRate apart.SecurityDeposit apart.Status
printfn "-----------------------------------------------------"

This would produce:

=====================================================
                        Monthly
Unit # Beds     Baths   Rent    Deposit Status
-----------------------------------------------------
101     2       2.00    1150    650     Available
102     1       1.00    950     500     NeedsRepair
103     1       1.00    925     500     Available
104     3       2.00    1350    850     Occupied
105     2       1.00    1150    550     Available
-----------------------------------------------------
Press any key to close this window . . .

Lists and Classes

Objects as Members of a List

The members of a list can be anything, as long as all of them are of the same type. This means that you can use the basis for members of a list. Of course you must have a class. You can use one of the classes of the .NET Framework or you can create your own class. You can then create objects of your chosen class and use those objects as members of a list. Here is an example:

type Employee(emplNbr, salary, monday, tuesday, wednesday, thursday, friday, saturday, sunday) =
    member val EmployeeNumber = emplNbr with get, set
    member val HourlySalary = salary with get, set
    member this.CalculateWeeklyTime() =
        monday + tuesday + wednesday + thursday + friday + saturday + sunday
    member this.CalculateWeeklySalary() =
        salary * this.CalculateWeeklyTime()
 
let empl1 = Employee("2080-4813", 22.25, 8.50, 9.50, 8.00, 10.00,  9.00, 0.00, 0.00)
let empl2 = Employee("4029-3940", 26.88, 8.00, 8.00, 8.00,  8.00,  8.00, 0.00, 0.00)
let empl3 = Employee("8485-2082", 15.55, 6.50, 7.00, 8.00,  6.00,  7.00, 0.00, 0.00)
let empl4 = Employee("3924-8816", 34.52, 9.00, 8.50, 9.50,  9.50, 10.00, 0.00, 0.00)
let empl5 = Employee("1831-2039", 25.55, 8.00, 6.50, 6.00,  6.00,  7.50, 0.00, 0.00)
 
let employeesPayrolls = [ empl1; empl2; empl3; empl4; empl5 ];

Instead of first declaring individual variables, you can create the objects directly in the list. Here is an example:

let employeesPayrolls = [
    Employee("2080-4813", 22.25, 8.50, 9.50, 8.00, 10.00,  9.00, 0.00, 0.00)
    Employee("4029-3940", 26.88, 8.00, 8.00, 8.00,  8.00,  8.00, 0.00, 0.00)
    Employee("8485-2082", 15.55, 6.50, 7.00, 8.00,  6.00,  7.00, 0.00, 0.00)
    Employee("3924-8816", 34.52, 9.00, 8.50, 9.50,  9.50, 10.00, 0.00, 0.00)
    Employee("1831-2039", 25.55, 8.00, 6.50, 6.00,  6.00,  7.50, 0.00, 0.00) ];

Either way, you can access the members of the class and use them as you see fit. Here is an example:

type Employee(emplNbr, salary, monday, tuesday, wednesday, thursday, friday, saturday, sunday) =
    member val EmployeeNumber = emplNbr with get, set
    member val HourlySalary = salary with get, set
    member this.CalculateWeeklyTime() =
        monday + tuesday + wednesday + thursday + friday + saturday + sunday
    member this.CalculateWeeklySalary() = salary * this.CalculateWeeklyTime()
 
let empl1 = Employee("2080-4813", 22.25, 8.50, 9.50, 8.00, 10.00,  9.00, 0.00, 0.00)
let empl2 = Employee("4029-3940", 26.88, 8.00, 8.00, 8.00,  8.00,  8.00, 0.00, 0.00)
let empl3 = Employee("8485-2082", 15.55, 6.50, 7.00, 8.00,  6.00,  7.00, 0.00, 0.00)
let empl4 = Employee("3924-8816", 34.52, 9.00, 8.50, 9.50,  9.50, 10.00, 0.00, 0.00)
let empl5 = Employee("1831-2039", 25.55, 8.00, 6.50, 6.00,  6.00,  7.50, 0.00, 0.00)
 
let employeesPayrolls = [ empl1; empl2; empl3; empl4; empl5 ];
printfn "Employee Payroll Summary"
printfn "===================================================="
printfn "Empl #\t\tSalary\tWeekly Time\tWeekly Salary"
printfn "----------------------------------------------------"
for empl in employeesPayrolls do
    printfn "%s\t%0.02f\t%0.02f\t\t%0.02F" empl.EmployeeNumber empl.HourlySalary (empl.CalculateWeeklyTime()) (empl.CalculateWeeklySalary())
printfn "===================================================="

This would produce:

Employee Payroll Summary
====================================================
Empl #          Salary  Weekly Time     Weekly Salary
----------------------------------------------------
2080-4813       22.25   45.00           1001.25
4029-3940       26.88   40.00           1075.20
8485-2082       15.55   34.50           536.48
3924-8816       34.52   46.50           1605.18
1831-2039       25.55   34.00           868.70
====================================================
Press any key to close this window . . .

As mentioned already, all the members of a list must be of the same type. You can use objects of different classes in a list. The main rule is that the classes must share a common ancestry.

In the same way, you can create many lists using a class, or you can create different lists using classes of your choice. Here are examples:

type Employee(emplNbr, salary) =
    member this.EmployeeNumber = emplNbr
    abstract member WeeklyTime : unit -> double
    default this.WeeklyTime() = 40.00
    abstract member WeeklySalary : unit -> double
    default this.WeeklySalary() = salary
 
type Salaried(emplNbr, salary, monday, tuesday, wednesday, thursday, friday, saturday, sunday) =
    inherit Employee(emplNbr, salary)
    member val HourlySalary = salary with get, set
    override this.WeeklyTime() =
        monday + tuesday + wednesday + thursday + friday + saturday + sunday
    override this.WeeklySalary() = salary * this.WeeklyTime()
 
let employeesPayrolls = [ Employee("9749-8075", 60000.00); Employee("2038-4051", 82000.00) ]
let salariedPayrolls  = [
      Salaried("2080-4813", 22.25, 8.50, 9.50, 8.00, 10.00,  9.00, 0.00, 0.00)
      Salaried("4029-3940", 26.88, 8.00, 8.00, 8.00,  8.00,  8.00, 0.00, 0.00)
      Salaried("8485-2082", 15.55, 6.50, 7.00, 8.00,  6.00,  7.00, 0.00, 0.00)
      Salaried("3924-8816", 34.52, 9.00, 8.50, 9.50,  9.50, 10.00, 0.00, 0.00)
      Salaried("1831-2039", 25.55, 8.00, 6.50, 6.00,  6.00,  7.50, 0.00, 0.00) ];
      
printfn "Fixed Salaried Employee Payroll"
printfn "===================================================="
printfn "           Weekly"
printfn "Empl #      Time    Yearly Salary"
printfn "----------------------------------------------------"
for empls in employeesPayrolls do
    printfn "%s    %0.0f       %0.0f" empls.EmployeeNumber (empls.WeeklyTime()) (empls.WeeklySalary())
printfn "====================================================\n"
 
printfn "Employee Payroll Summary"
printfn "===================================================="
printfn "Empl #\t\tSalary\tWeekly Time\tWeekly Salary"
printfn "----------------------------------------------------"
for empls in salariedPayrolls do
    printfn "%s\t%0.02f\t%0.02f\t\t%0.02F" empls.EmployeeNumber empls.HourlySalary (empls.WeeklyTime()) (empls.WeeklySalary())
printfn "===================================================="

This would produce:

Fixed Salaried Employee Payroll
====================================================
           Weekly
Empl #      Time    Yearly Salary
----------------------------------------------------
9749-8075    40       60000
2038-4051    40       82000
====================================================
 
Employee Payroll Summary
====================================================
Empl #          Salary  Weekly Time     Weekly Salary
----------------------------------------------------
2080-4813       22.25   45.00           1001.25
4029-3940       26.88   40.00           1075.20
8485-2082       15.55   34.50           536.48
3924-8816       34.52   46.50           1605.18
1831-2039       25.55   34.00           868.70
====================================================
Press any key to close this window . . .

In the same way, you can create a list in a list (or a list in a list in a list...) or a list of lists (or a list of lists of lists...). Here is an example:

let employeesPayrolls = [
    [ Employee("9749-8075", 60000.00); Employee("2038-4051", 82000.00) ]
    [
        Salaried("2080-4813", 22.25, 8.50, 9.50, 8.00, 10.00,  9.00, 0.00, 0.00)
        Salaried("4029-3940", 26.88, 8.00, 8.00, 8.00,  8.00,  8.00, 0.00, 0.00)
        Salaried("8485-2082", 15.55, 6.50, 7.00, 8.00,  6.00,  7.00, 0.00, 0.00)
        Salaried("3924-8816", 34.52, 9.00, 8.50, 9.50,  9.50, 10.00, 0.00, 0.00)
        Salaried("1831-2039", 25.55, 8.00, 6.50, 6.00,  6.00,  7.50, 0.00, 0.00)
    ]
];

A List as a Property

A property of a class can be created from a list. We already know that a list can be passed to a function. This means that a parameter passed to the constructor of a class can represent a list. You can then use that parameter and assign it to a property. Here are examples:

type EmployeePayroll(emplNbr, name, salary, times) =
    member val EmployeeNumber = emplNbr with get, set
    member val FullName = name with get, set
    member val HourlySalary = salary with get, set
    member val WeeklyTimes = times with get, set

Once again, from these properties, the compiler doesn't know the data type of each parameter and a parameter can be anything. This also means that the compiler doesn't know whether a parameter is a list or not. When creating an object from the class, you can pass a list in the placeholder of an argument. Here are examples:

let ep = EmployeePayroll("2080-4813", [ "James"; "Roland"; "Alexanders" ], 22.25, [ 8.50; 9.50; 8.00; 10.00; 9.00; 0.00; 0.00 ])

From that object, the compiler can infer the appropriate type of each parameter. You can then use each property as you see fit. Here are examples:

type EmployeePayroll(emplNbr, name, salary, times) =
    member val EmployeeNumber = emplNbr with get, set
    member val FullName = name with get, set
    member val HourlySalary = salary with get, set
    member val WeeklyTimes = times with get, set
 
let ep = EmployeePayroll("2080-4813", [ "James"; "Roland"; "Alexanders" ], 22.25, [ 8.50; 9.50; 8.00; 10.00; 9.00; 0.00; 0.00 ])
 
printfn "Employee Payroll Summary"
printfn "----------------------------------------------------"
printfn "Employee #:    %s" ep.EmployeeNumber
printfn "Full Name:     %A" ep.FullName
printfn "Hourly Salary: %0.02F" ep.HourlySalary
printfn "Time Worked:   %A" ep.WeeklyTimes
printfn "----------------------------------------------------"

This would produce:

Employee Payroll Summary
----------------------------------------------------
Employee #:    2080-4813
Full Name:     ["James"; "Roland"; "Alexanders"]
Hourly Salary: 22.25
Time Worked:   [8.5; 9.5; 8.0; 10.0; 9.0; 0.0; 0.0]
----------------------------------------------------
Press any key to close this window . . .

Remember that you can use a loop to access each member of a list. In the same way, once you have the value of a listed property, treat it as such. Here are examples:

type EmployeePayroll(emplNbr, name, salary, times) =
    member val EmployeeNumber = emplNbr with get, set
    member val FullName = name with get, set
    member val HourlySalary = salary with get, set
    member val WeeklyTimes = times with get, set
 
let ep = EmployeePayroll("2080-4813", [ "James"; "Roland"; "Alexanders" ], 22.25, [ 8.50; 9.50; 8.00; 10.00; 9.00; 0.00; 0.00])
 
printfn "Employee Payroll Summary"
printfn "----------------------------------------------------"
printfn "Employee #:    %s" ep.EmployeeNumber
printf "Full Name:     "
for name in ep.FullName do
    printf "%s " name
printfn "\nHourly Salary: %0.02F" ep.HourlySalary
printf "Time Worked:   "
for time in ep.WeeklyTimes do
    printf "%0.02f " time
printfn "\n----------------------------------------------------"

This would produce:

Employee Payroll Summary
----------------------------------------------------
Employee #:    2080-4813
Full Name:     James Roland Alexanders
Hourly Salary: 22.25
Time Worked:   8.50 9.50 8.00 10.00 9.00 0.00 0.00
----------------------------------------------------
Press any key to close this window . . .

Operations on a List

Getting an Item Based on Its Index

As an alternative to the List.Item property, the List module is equipped with a static member function named nth. Its syntax is:

List.nth : 'T list -> int -> 'T

This function takes two arguments: a list variable and the index + 1 of the member you want to access. Here is an example of calling it:

let numbers = [3 .. 2 .. 20 ]
printfn "Numbers: %A\n" numbers

let sixth = List.nth numbers 5
printfn "6th Member: %d\n" sixth

Remember that the first item is located at index 0. Here is an example:

type EmploymentStatus =
    | Unknown  = 0
    | FullTime = 1
    | PartTime = 2
    | Intern   = 3
    | Seasonal = 4
     
type Employee(emplNbr, status, salary) =
    member this.EmployeeNumber = emplNbr
    member this.EmploymentStatus : EmploymentStatus = status
    abstract member WeeklyTime : unit -> double
    default this.WeeklyTime() = 40.00
    abstract member WeeklySalary : unit -> double
    default this.WeeklySalary() = salary
 
let employeesPayrolls = [ Employee("2405-8296", EmploymentStatus.Seasonal, 35400.00); Employee("2813-3044", EmploymentStatus.PartTime, 32500.00);
                          Employee("2903-0481", EmploymentStatus.FullTime, 88500.00); Employee("5020-4681", EmploymentStatus.FullTime, 65200.00); ]
 
let payroll = List.tail employeesPayrolls
 
printfn "Fixed Salaried Employee Payroll"
printfn "==================================="
printfn "           Weekly \tYearly"
printfn "Empl #      Time\tSalary"
printfn "-----------------------------------"
for i = 0 to employeesPayrolls.Length - 1 do
    printfn "%s  %A\t%0.0f" (List.nth employeesPayrolls i).EmployeeNumber (List.nth employeesPayrolls i).EmploymentStatus ((List.nth employeesPayrolls i).WeeklySalary())
printfn "===================================\n"

This would produce:

Fixed Salaried Employee Payroll
===================================
           Weekly       Yearly
Empl #      Time        Salary
-----------------------------------
2405-8296  Seasonal     35400
2813-3044  PartTime     32500
2903-0481  FullTime     88500
5020-4681  FullTime     65200
===================================

Press any key to close this window . . .

Iterating Through a List

Iterating through a list consists of executing a function on each member of the list. One of the List functions used to perform this operation is called iter. Its signature is:

List.iter : ('T -> unit) -> 'T list -> unit

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

type EmploymentStatus =
    | Unknown  = 0
    | FullTime = 1
    | PartTime = 2
    | Intern   = 3
    | Seasonal = 4
     
type Employee(emplNbr, status, salary) =
    member this.EmployeeNumber = emplNbr
    member this.EmploymentStatus : EmploymentStatus = status
    member this.YearlySalary = salary
 
let employees = [ Employee("9749-8075", EmploymentStatus.FullTime, 60000.00); Employee("2038-4051", EmploymentStatus.FullTime, 82000.00);
                  Employee("2405-8296", EmploymentStatus.Seasonal, 35400.00); Employee("2813-3044", EmploymentStatus.PartTime, 32500.00);
                  Employee("2903-0481", EmploymentStatus.FullTime, 88500.00); Employee("5020-4681", EmploymentStatus.FullTime, 65200.00); ]
 
printfn "Fixed Salaried Employee Payroll"
printfn "==================================="
printfn "           Employment   \tYearly"
printfn "Empl #      Status\tSalary"
printfn "-----------------------------------"

List.iter (fun (empl : Employee) -> printfn "%s  %A\t%0.0f" empl.EmployeeNumber empl.EmploymentStatus empl.YearlySalary) employees

This would produce:

Fixed Salaried Employee Payroll
===================================
           Employment   Yearly
Empl #      Status      Salary
-----------------------------------
9749-8075  FullTime     60000
2038-4051  FullTime     82000
2405-8296  Seasonal     35400
2813-3044  PartTime     32500
2903-0481  FullTime     88500
5020-4681  FullTime     65200
Press any key to close this window . . .

The First Member of a List

To let you get the first member of a list, the List union provides a property named Head. Here is an example of using this property:

let numbers = [3 .. 2 .. 20 ]
printfn "Numbers: %A\n" numbers

let first = numbers.Head;
printfn "First Member: %d\n" first

This would produce:

Numbers: [3; 5; 7; 9; 11; 13; 15; 17; 19]
 
First Member: 3
 
Press any key to close this window . . .

To support this, the List module is equipped with a function named head. Its signature is:

List.head : 'T list -> 'T

Here is an example:

type EmploymentStatus =
    | Unknown  = 0
    | FullTime = 1
    | PartTime = 2
    | Intern   = 3
    | Seasonal = 4
     
type Employee(emplNbr, status, salary) =
    member this.EmployeeNumber = emplNbr
    member this.EmploymentStatus : EmploymentStatus = status
    abstract member WeeklyTime : unit -> double
    default this.WeeklyTime() = 40.00
    abstract member WeeklySalary : unit -> double
    default this.WeeklySalary() = salary
 
let employeesPayrolls = [ Employee("9749-8075", EmploymentStatus.FullTime, 60000.00); Employee("2038-4051", EmploymentStatus.FullTime, 82000.00);
                          Employee("2405-8296", EmploymentStatus.Seasonal, 35400.00); Employee("2813-3044", EmploymentStatus.PartTime, 32500.00); ]
 
let payroll = List.head employeesPayrolls
 
printfn "Employee Payroll"
printfn "==================================="
printfn "Employee #:    %s" payroll.EmployeeNumber
printfn "Status:        %A" payroll.EmploymentStatus
printfn "Yearly Salary: %0.0f" (payroll.WeeklySalary())
printfn "===================================\n"

This would produce:

Employee Payroll
===================================
Employee #:    9749-8075
Status:        FullTime
Yearly Salary: 60000
===================================

Press any key to close this window . . .

The Tail of a List

To let you get the list without the first item, the List union provides a property named Tail. Here is an example of using it:

let numbers = [3 .. 2 .. 20 ]
printfn "Numbers: %A\n" numbers

let freeOne = numbers.Tail
printfn "List without first member: %A\n" freeOne

This would produce:

Numbers: [3; 5; 7; 9; 11; 13; 15; 17; 19]
 
List without first member: [5; 7; 9; 11; 13; 15; 17; 19]
 
Press any key to close this window . . .

To support the tail of a list, the List module has a function named tail. Its signature is:

List.tail : 'T list -> 'T list

Remember that the tail in this case is the list of items from the argument but without the first element. Here is an example:

type EmploymentStatus =
    | Unknown  = 0
    | FullTime = 1
    | PartTime = 2
    | Intern   = 3
    | Seasonal = 4
     
type Employee(emplNbr, status, salary) =
    member this.EmployeeNumber = emplNbr
    member this.EmploymentStatus : EmploymentStatus = status
    abstract member WeeklyTime : unit -> double
    default this.WeeklyTime() = 40.00
    abstract member WeeklySalary : unit -> double
    default this.WeeklySalary() = salary
 
let employeesPayrolls = [ Employee("9749-8075", EmploymentStatus.FullTime, 60000.00); Employee("2038-4051", EmploymentStatus.FullTime, 82000.00);
                          Employee("5031-9259", EmploymentStatus.FullTime, 55000.00); Employee("7092-3094", EmploymentStatus.FullTime, 104000.00);
                          Employee("2903-0481", EmploymentStatus.FullTime, 88500.00); Employee("5020-4681", EmploymentStatus.FullTime, 65200.00); ]
 
let payroll = List.tail employeesPayrolls
 
printfn "Fixed Salaried Employee Payroll"
printfn "==================================="
printfn "           Weekly \tYearly"
printfn "Empl #      Time\tSalary"
printfn "-----------------------------------"
for pay in employeesPayrolls do
    printfn "%s  %A\t%0.0f" pay.EmployeeNumber pay.EmploymentStatus (pay.WeeklySalary())
printfn "===================================\n"

This would produce:

Fixed Salaried Employee Payroll
===================================
           Weekly       Yearly
Empl #      Time        Salary
-----------------------------------
9749-8075  FullTime     60000
2038-4051  FullTime     82000
5031-9259  FullTime     55000
7092-3094  FullTime     104000
2903-0481  FullTime     88500
5020-4681  FullTime     65200
===================================

Press any key to close this window . . .

The Last Member of a List

To get the last member of a list, you can call the List.Item property and pass the Length property - 1. Here is an example:

let numbers = [3 .. 2 .. 20 ]
printfn "Numbers: %A\n" numbers
 
let last = numbers.Item(numbers.Length - 1);
printfn "Last Member: %d\n" last

This would produce:

Numbers: [3; 5; 7; 9; 11; 13; 15; 17; 19]
 
Last Member: 19

Press any key to close this window . . .

Replacing the First Member of a List

The List union is equipped with a static method used to create a new list by specifying the first member of your choice and existing members from another list. The method is called Cons. Its signature is:

static member List.Cons : 'T * 'T list -> 'T list

This method takes two arguments and returns a list. The first argument is the value that will be used as the first in the new list. The second argument is the list to which the first argument will be added. Here is an example of calling it:

let numbers = [3 .. 2 .. 20 ]
printfn "Numbers: %A\n" numbers
 
let additional = List.Cons(228, numbers.Tail)
printfn "Numbers: %A\n" additional

This would produce:

Numbers: [3; 5; 7; 9; 11; 13; 15; 17; 19]
 
Numbers: [228; 5; 7; 9; 11; 13; 15; 17; 19]

Press any key to close this window . . .

If an Element Exists in a List

To let you find out whether a certain element exists in a list, the List module is equipped with a method named exists. Its signature is:

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

Here is an example of calling this method:

type EmploymentStatus =
    | Unknown  = 0
    | FullTime = 1
    | PartTime = 2
    | Intern   = 3
    | Seasonal = 4
     
type Employee(emplNbr, status, salary) =
    member this.EmployeeNumber = emplNbr
    member this.EmploymentStatus : EmploymentStatus = status
    abstract member WeeklyTime : unit -> double
    default this.WeeklyTime() = 40.00
    abstract member WeeklySalary : unit -> double
    default this.WeeklySalary() = salary
 
let employeesPayrolls = [ Employee("9749-8075", EmploymentStatus.FullTime, 60000.00); Employee("2038-4051", EmploymentStatus.FullTime, 82000.00);
                          Employee("2405-8296", EmploymentStatus.Seasonal, 35400.00); Employee("2813-3044", EmploymentStatus.PartTime, 32500.00);
                          Employee("2903-0481", EmploymentStatus.FullTime, 88500.00); Employee("5020-4681", EmploymentStatus.FullTime, 65200.00); ]
 
let exists nbr list : bool = List.exists (fun (empl : Employee) -> empl.EmployeeNumber = nbr) list
 
let result = exists "2405-8296" employeesPayrolls
printfn "The employee exists: %b" result

This would produce:

The employee exists: true
Press any key to close this window . . .

In our example, we defined a function. As an alternative, we could simply have provided the arguments when calling the List.exists() method:

let res = List.exists (fun (empl : Employee) -> empl.EmployeeNumber = "2405-8296") employeesPayrolls

To let you compare elements from two different lists by their corresponding positions, the List module provides a function named exists2. Its signature is:

List.exists2 : ('T1 -> 'T2 -> bool) -> 'T1 list -> 'T2 list -> bool

Applying a Condition to all Items

To let you apply a certain condition to all elements of a list, the List module is equipped with a function named forAll. Its signature is:

List.forall : ('T -> bool) -> 'T list -> bool

This function takes two arguments. The first arguments is a Boolean function to apply to the second argument. If at least one item of the list responds to the condition in the first argument, the function returns true. Here is an example:

type EmploymentStatus =
    | Unknown  = 0
    | FullTime = 1
    | PartTime = 2
    | Intern   = 3
    | Seasonal = 4
     
type Employee(emplNbr, status, salary) =
    member this.EmployeeNumber = emplNbr
    member this.EmploymentStatus : EmploymentStatus = status
    member this.YearlySalary = salary
 
let employees = [ Employee("9749-8075", EmploymentStatus.FullTime, 60000.00); Employee("2038-4051", EmploymentStatus.FullTime, 82000.00);
                  Employee("5031-9259", EmploymentStatus.FullTime, 55000.00); Employee("7092-3094", EmploymentStatus.FullTime, 104000.00); ]
 
let areFullTimers = List.forall (fun (empl : Employee) -> empl.EmploymentStatus = EmploymentStatus.FullTime) employees;
 
printfn "Are all employees full-times? %b" areFullTimers

This would produce:

Are all employees full-times? true
Press any key to close this window . . .

Here is another example:

type EmploymentStatus =
    | Unknown  = 0
    | FullTime = 1
    | PartTime = 2
    | Intern   = 3
    | Seasonal = 4
     
type Employee(emplNbr, status, salary) =
    member this.EmployeeNumber = emplNbr
    member this.EmploymentStatus : EmploymentStatus = status
    member this.YearlySalary = salary
 
let employees = [ Employee("9749-8075", EmploymentStatus.FullTime, 60000.00); Employee("2038-4051", EmploymentStatus.FullTime, 82000.00);
                  Employee("5031-9259", EmploymentStatus.FullTime, 55000.00); Employee("7092-3094", EmploymentStatus.FullTime, 104000.00);
                  Employee("2405-8296", EmploymentStatus.Seasonal, 35400.00); Employee("2813-3044", EmploymentStatus.PartTime, 32500.00);
                  Employee("2903-0481", EmploymentStatus.FullTime, 88500.00); Employee("5020-4681", EmploymentStatus.FullTime, 65200.00);
                  Employee("2903-0481", EmploymentStatus.FullTime, 88500.00); Employee("5020-4681", EmploymentStatus.FullTime, 65200.00); ]
 
let areFullTimers = List.forall (fun (empl : Employee) -> empl.EmploymentStatus = EmploymentStatus.FullTime) employees;
 
if areFullTimers = true then
    printfn "Are all employees full-times? Yes"
else
    printfn "Are all employees full-times? No"

This would produce:

Are all employees full-times? No
Press any key to close this window . . .

Finding an Item in a List

To assist you with finding an item in a list, the List module provides a function named find. Its signature is:

List.find : ('T -> bool) -> 'T list -> 'T

Here are examples:

type EmploymentStatus =
    | Unknown  = 0
    | FullTime = 1
    | PartTime = 2
    | Intern   = 3
    | Seasonal = 4
     
type Employee(emplNbr, status, salary) =
    member this.EmployeeNumber = emplNbr
    member this.EmploymentStatus : EmploymentStatus = status
    member this.YearlySalary = salary
 
let employees = [ Employee("9749-8075", EmploymentStatus.FullTime, 60000); Employee("2038-4051", EmploymentStatus.FullTime, 82000);
                  Employee("2405-8296", EmploymentStatus.Seasonal, 35400); Employee("2813-3044", EmploymentStatus.PartTime, 25500);
                  Employee("5031-9259", EmploymentStatus.FullTime, 25500); Employee("7092-3094", EmploymentStatus.FullTime, 104000); ]
 
let found = List.find (fun (empl : Employee) -> empl.EmployeeNumber = "2405-8296") employees
 
printfn "Employee Record"
printfn "==================================="
printfn "Employee #:    %s" found.EmployeeNumber
printfn "Status:        %A" found.EmploymentStatus
printfn "Yearly Salary: %i" found.YearlySalary
printfn "-----------------------------------"

This would produce:

Employee Record
===================================
Employee #:    2405-8296
Status:        Seasonal
Yearly Salary: 35400
-----------------------------------
Press any key to close this window . . .

Picking an Item from a List

Picking an item from a list consists of applying a condition to it and selecting the first item that responds to that condition. To support this operation, the List module is equipped with a function named pick. Its signature is:

List.pick : ('T -> 'U option) -> 'T list -> 'U

This function takes two arguments. The first argument requires a matching condition and the second is the list that holds the items. Here is an example:

type EmploymentStatus =
    | Unknown  = 0
    | FullTime = 1
    | PartTime = 2
    | Intern   = 3
    | Seasonal = 4
     
type Employee(emplNbr, status, salary) =
    member this.EmployeeNumber = emplNbr
    member this.EmploymentStatus : EmploymentStatus = status
    member this.YearlySalary = salary
 
let employees = [ Employee("9749-8075", EmploymentStatus.FullTime, 60000.00); Employee("2928-7947", EmploymentStatus.PartTime, 30700.00);
                  Employee("2038-4051", EmploymentStatus.FullTime, 82000.00); Employee("5503-0485", EmploymentStatus.PartTime, 39580.00);
                  Employee("2405-8296", EmploymentStatus.Seasonal, 35400.00); Employee("2813-3044", EmploymentStatus.PartTime, 15700.00);
                  Employee("5031-9259", EmploymentStatus.FullTime, 25500.00); Employee("7092-3094", EmploymentStatus.FullTime, 104000.00); ]
 
let picker = List.pick (fun (empl : Employee) -> 
    match empl.EmploymentStatus with
    | EmploymentStatus.PartTime -> Some(empl)
    | _ -> None) employees
 
printfn "Employee Record"
printfn "==================================="
printfn "Employee #:    %s" picker.EmployeeNumber
printfn "Status:        %A" picker.EmploymentStatus
printfn "Yearly Salary: %0.0f" picker.YearlySalary
printfn "-----------------------------------"

This would produce:

Employee Record
===================================
Employee #:    2928-7947
Status:        PartTime
Yearly Salary: 30700
-----------------------------------
Press any key to close this window . . .

Sub-Lists

Filtering by Some Items

A sub-list is a list derived from an existing list. To create a sub-list, you have many options.

To select some items from a list, you can apply a criterion that would filter some items, put them in a new list, and return that list. To support this operation, the List module provides a function named filter. Its signature is:

List.filter : ('T -> bool) -> 'T list -> 'T list

This function takes a function and a list as arguments. The internal function applies a condition to each item of the list. Every item that responds to the condition is put in a new list. At the end, that list is returned from the List.filter() function. Here is an example:

type OccupancyStatus =
| Other
| Available
| Occupied
| NeedsRepair

type Apartment = {
    UnitNumber      : string
    Bedrooms        : int
    Bathrooms       : float
    SecurityDeposit : int
    MonthlyRate     : int
    Status          : OccupancyStatus }

let apartments = [
    { UnitNumber = "101"; Bedrooms = 2; Bathrooms = 2.00; SecurityDeposit = 650; MonthlyRate = 1150; Status = OccupancyStatus.Available   }
    { UnitNumber = "102"; Bedrooms = 1; Bathrooms = 1.00; SecurityDeposit = 500; MonthlyRate =  950; Status = OccupancyStatus.NeedsRepair }
    { UnitNumber = "103"; Bedrooms = 1; Bathrooms = 1.00; SecurityDeposit = 500; MonthlyRate =  925; Status = OccupancyStatus.Available   }
    { UnitNumber = "104"; Bedrooms = 3; Bathrooms = 2.00; SecurityDeposit = 850; MonthlyRate = 1350; Status = OccupancyStatus.Occupied    }
    { UnitNumber = "105"; Bedrooms = 2; Bathrooms = 1.00; SecurityDeposit = 550; MonthlyRate = 1150; Status = OccupancyStatus.Available   }
    { UnitNumber = "106"; Bedrooms = 3; Bathrooms = 1.50; SecurityDeposit = 950; MonthlyRate = 1425; Status = OccupancyStatus.NeedsRepair }
    { UnitNumber = "107"; Bedrooms = 1; Bathrooms = 1.00; SecurityDeposit = 500; MonthlyRate =  950; Status = OccupancyStatus.Occupied    }
    { UnitNumber = "108"; Bedrooms = 2; Bathrooms = 1.00; SecurityDeposit = 550; MonthlyRate = 1150; Status = OccupancyStatus.Occupied    }
 ]

let ready = List.filter (fun (apart : Apartment) -> apart.Status = OccupancyStatus.Available) apartments

printfn "====================================================="
printfn "\t\t\tMonthly"
printfn "Unit # Beds\tBaths\tRent\tDeposit Status"
printfn "-----------------------------------------------------"
for apart in ready do
    printfn "%s\t%i\t%.2f\t%d\t%d\t%A" apart.UnitNumber apart.Bedrooms apart.Bathrooms apart.MonthlyRate apart.SecurityDeposit apart.Status
printfn "-----------------------------------------------------"

This would produce:

=====================================================
                        Monthly
Unit # Beds     Baths   Rent    Deposit Status
-----------------------------------------------------
101     2       2.00    1150    650     Available
103     1       1.00    925     500     Available
105     2       1.00    1150    550     Available
-----------------------------------------------------
Press any key to close this window . . .

Choosing a Sub-List

Choosing a sub-list consists of applying a criterion to an existing list. The elements that respond to the condition would be selected and added to the new list. To assist you with this, the List module is equipped with a function named choose. Its signature is:

List.choose : ('T -> 'U option) -> 'T list -> 'U list

This function takes two arguments. The first is a function that includes a matching conditional statement. The second argument is the list on which the condition will be applied. Here is an example:

type EmploymentStatus =
    | Unknown  = 0
    | FullTime = 1
    | PartTime = 2
    | Intern   = 3
    | Seasonal = 4
     
type Employee(emplNbr, status, salary) =
    member this.EmployeeNumber = emplNbr
    member this.EmploymentStatus : EmploymentStatus = status
    abstract member YearlySalary : unit -> double
    default this.YearlySalary() = salary
 
let employeesPayrolls = [ Employee("9749-8075", EmploymentStatus.FullTime, 60000.00); Employee("2038-4051", EmploymentStatus.FullTime, 82000.00);
                          Employee("2405-8296", EmploymentStatus.Seasonal, 35400.00); Employee("2813-3044", EmploymentStatus.PartTime, 32500.00);
                          Employee("2903-0481", EmploymentStatus.FullTime, 88500.00); Employee("5020-4681", EmploymentStatus.FullTime, 65200.00); ]
 
let choose = List.choose (fun (empl : Employee) -> 
    match empl.EmploymentStatus with
    | EmploymentStatus.FullTime -> Some(empl)
    | _ -> None) employeesPayrolls
 
printfn "Employees Salary Summary"
printfn "=============================="
printfn "           \tYearly"
printfn "Empl #     \tSalary"
printfn "------------------------------"
for i = 0 to choose.Length - 1 do
    printfn "%s  \t%0.0f" (List.nth choose i).EmployeeNumber ((List.nth choose i).YearlySalary())
printfn "==============================\n"

This would produce:

Employees Salary Summary
==============================
                Yearly
Empl #          Salary
------------------------------
9749-8075       60000
2038-4051       82000
2903-0481       88500
5020-4681       65200
==============================
 
Press any key to close this window . . .

Mapping Some Elements

Mapping elements consists of applying a condition on each element of a list to select only the items that follow that condition to produce a new derived list. To let you perform this operation, the List module provides a function named map. Its signature is:

List.map : ('T -> 'U) -> 'T list -> 'U list

Here is an example:

type EmploymentStatus =
    | Unknown  = 0
    | FullTime = 1
    | PartTime = 2
    | Intern   = 3
    | Seasonal = 4

type Employee(emplNbr, status, salary) =
    member this.EmployeeNumber = emplNbr
    member this.EmploymentStatus : EmploymentStatus = status
    member this.YearlySalary = salary
 
let employees = [ Employee("9749-8075", EmploymentStatus.FullTime, 60000.00); Employee("2038-4051", EmploymentStatus.FullTime,  82000.00);
                  Employee("2405-8296", EmploymentStatus.Seasonal, 35400.00); Employee("2813-3044", EmploymentStatus.PartTime,  15700.00);
                  Employee("5031-9259", EmploymentStatus.FullTime, 25500.00); Employee("7092-3094", EmploymentStatus.FullTime, 104000.00); ]
 
let mapped = List.map (fun (empl : Employee) -> empl.YearlySalary) employees
printfn "Salaries: %A" mapped;

This would produce:

Salaries: [60000.0; 82000.0; 35400.0; 15700.0; 25500.0; 104000.0]
ress any key to continue . . .

Partitioning a List

Particitioning a list consists of creating two lists derived from an existing one. To do this, you apply a condition to an existing list. The items that respond to the condition are put in a new list. The items that don't respond to the condition are put in another new list. To support this ôperation, the List module provides a function named partition. Its signature is:

List.partition : ('T -> bool) -> 'T list -> 'T list * 'T list

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

type OccupancyStatus =
| Other
| Available
| Occupied
| NeedsRepair

type Apartment = {
    UnitNumber      : string
    Bedrooms        : int
    Bathrooms       : float
    SecurityDeposit : int
    MonthlyRate     : int
    Status          : OccupancyStatus }

let apartments = [
    { UnitNumber = "101"; Bedrooms = 2; Bathrooms = 2.00; SecurityDeposit = 650; MonthlyRate = 1150; Status = OccupancyStatus.Available   }
    { UnitNumber = "102"; Bedrooms = 1; Bathrooms = 1.00; SecurityDeposit = 500; MonthlyRate =  950; Status = OccupancyStatus.NeedsRepair }
    { UnitNumber = "103"; Bedrooms = 1; Bathrooms = 1.00; SecurityDeposit = 500; MonthlyRate =  925; Status = OccupancyStatus.Available   }
    { UnitNumber = "104"; Bedrooms = 3; Bathrooms = 2.00; SecurityDeposit = 850; MonthlyRate = 1350; Status = OccupancyStatus.Occupied    }
    { UnitNumber = "105"; Bedrooms = 2; Bathrooms = 1.00; SecurityDeposit = 550; MonthlyRate = 1150; Status = OccupancyStatus.Available   }
    { UnitNumber = "106"; Bedrooms = 3; Bathrooms = 1.50; SecurityDeposit = 950; MonthlyRate = 1425; Status = OccupancyStatus.NeedsRepair }
    { UnitNumber = "107"; Bedrooms = 1; Bathrooms = 1.00; SecurityDeposit = 500; MonthlyRate =  950; Status = OccupancyStatus.Occupied    }
    { UnitNumber = "108"; Bedrooms = 2; Bathrooms = 1.00; SecurityDeposit = 550; MonthlyRate = 1150; Status = OccupancyStatus.Occupied    }
 ]

let (ready, not) = List.partition (fun (apart : Apartment) -> apart.Status = OccupancyStatus.Available) apartments

printfn "====================================================="
printfn "Available Apartments"
printfn "\t\t\tMonthly"
printfn "Unit # Beds\tBaths\tRent\tDeposit Status"
printfn "-----------------------------------------------------"
for apart in ready do
    printfn "%s\t%i\t%.2f\t%d\t%d\t%A" apart.UnitNumber apart.Bedrooms apart.Bathrooms apart.MonthlyRate apart.SecurityDeposit apart.Status
printfn "-----------------------------------------------------"
printfn "====================================================="
printfn "Apartments not Available"
printfn "\t\t\tMonthly"
printfn "Unit # Beds\tBaths\tRent\tDeposit Status"
printfn "-----------------------------------------------------"
for apart in not do
    printfn "%s\t%i\t%.2f\t%d\t%d\t%A" apart.UnitNumber apart.Bedrooms apart.Bathrooms apart.MonthlyRate apart.SecurityDeposit apart.Status
printfn "-----------------------------------------------------"

This would produce:

=====================================================
Available Apartments
                        Monthly
Unit # Beds     Baths   Rent    Deposit Status
-----------------------------------------------------
101     2       2.00    1150    650     Available
103     1       1.00    925     500     Available
105     2       1.00    1150    550     Available
-----------------------------------------------------
=====================================================
Apartments not Available
                        Monthly
Unit # Beds     Baths   Rent    Deposit Status
-----------------------------------------------------
102     1       1.00    950     500     NeedsRepair
104     3       2.00    1350    850     Occupied
106     3       1.50    1425    950     NeedsRepair
107     1       1.00    950     500     Occupied
108     2       1.00    1150    550     Occupied
-----------------------------------------------------
Press any key to close this window . . .

Notice that the List.partition() function returns a tuple pair whose two elements are a list each. If one of both tuple members holds a list whose members can be segmented based on certain criterion, you can call the function on that member to get another tuple with sub-lists. Here is an example:

type OccupancyStatus =
| Other
| Available
| Occupied
| NeedsRepair

type Apartment = {
    UnitNumber      : string
    Bedrooms        : int
    Bathrooms       : float
    SecurityDeposit : int
    MonthlyRate     : int
    Status          : OccupancyStatus }

let apartments = [
    { UnitNumber = "101"; Bedrooms = 2; Bathrooms = 2.00; SecurityDeposit = 650; MonthlyRate = 1150; Status = OccupancyStatus.Available   }
    { UnitNumber = "102"; Bedrooms = 1; Bathrooms = 1.00; SecurityDeposit = 500; MonthlyRate =  950; Status = OccupancyStatus.NeedsRepair }
    { UnitNumber = "103"; Bedrooms = 1; Bathrooms = 1.00; SecurityDeposit = 500; MonthlyRate =  925; Status = OccupancyStatus.Available   }
    { UnitNumber = "104"; Bedrooms = 3; Bathrooms = 2.00; SecurityDeposit = 850; MonthlyRate = 1350; Status = OccupancyStatus.Occupied    }
    { UnitNumber = "105"; Bedrooms = 2; Bathrooms = 1.00; SecurityDeposit = 550; MonthlyRate = 1150; Status = OccupancyStatus.Available   }
    { UnitNumber = "106"; Bedrooms = 3; Bathrooms = 1.50; SecurityDeposit = 950; MonthlyRate = 1425; Status = OccupancyStatus.NeedsRepair }
    { UnitNumber = "107"; Bedrooms = 1; Bathrooms = 1.00; SecurityDeposit = 500; MonthlyRate =  950; Status = OccupancyStatus.Occupied    }
    { UnitNumber = "108"; Bedrooms = 2; Bathrooms = 1.00; SecurityDeposit = 550; MonthlyRate = 1150; Status = OccupancyStatus.Occupied    }
 ]

//let (ready, not) = List.partition (fun (apart : Apartment) -> apart.Status = OccupancyStatus.Available) apartments
let (notAvailable, available) = List.partition (fun (apart : Apartment) -> apart.Status <> OccupancyStatus.Available) apartments
let (occupied, needsRepair) = List.partition (fun (apart : Apartment) -> apart.Status = OccupancyStatus.Occupied) notAvailable

printfn "====================================================="
printfn "Available Apartments"
printfn "\t\t\tMonthly"
printfn "Unit # Beds\tBaths\tRent\tDeposit Status"
printfn "-----------------------------------------------------"
for apart in available do
    printfn "%s\t%i\t%.2f\t%d\t%d\t%A" apart.UnitNumber apart.Bedrooms apart.Bathrooms apart.MonthlyRate apart.SecurityDeposit apart.Status
printfn "-----------------------------------------------------"
printfn "Occupied Apartments"
printfn "\t\t\tMonthly"
printfn "Unit # Beds\tBaths\tRent\tDeposit Status"
printfn "-----------------------------------------------------"
for apart in occupied do
    printfn "%s\t%i\t%.2f\t%d\t%d\t%A" apart.UnitNumber apart.Bedrooms apart.Bathrooms apart.MonthlyRate apart.SecurityDeposit apart.Status
printfn "-----------------------------------------------------"
printfn "Apartments that need repair"
printfn "\t\t\tMonthly"
printfn "Unit # Beds\tBaths\tRent\tDeposit Status"
printfn "-----------------------------------------------------"
for apart in needsRepair do
    printfn "%s\t%i\t%.2f\t%d\t%d\t%A" apart.UnitNumber apart.Bedrooms apart.Bathrooms apart.MonthlyRate apart.SecurityDeposit apart.Status
printfn "-----------------------------------------------------"

This would produce:

=====================================================
Available Apartments
                        Monthly
Unit # Beds     Baths   Rent    Deposit Status
-----------------------------------------------------
101     2       2.00    1150    650     Available
103     1       1.00    925     500     Available
105     2       1.00    1150    550     Available
-----------------------------------------------------
Occupied Apartments
                        Monthly
Unit # Beds     Baths   Rent    Deposit Status
-----------------------------------------------------
104     3       2.00    1350    850     Occupied
107     1       1.00    950     500     Occupied
108     2       1.00    1150    550     Occupied
-----------------------------------------------------
Apartments that need repair
                        Monthly
Unit # Beds     Baths   Rent    Deposit Status
-----------------------------------------------------
102     1       1.00    950     500     NeedsRepair
106     3       1.50    1425    950     NeedsRepair
-----------------------------------------------------
Press any key to close this window . . .

Numeric Operations on Elements

The Sum of Values of a List

If you have a list made of numeric values, to let you get the sum of those values, the List module provides a function named sum. Its syntax is:

List.sum : ^T list -> ^T (requires ^T with static member (+) and ^T with static member Zero)

Here are examples:

let timesWorked = ([8.00; 9.00; 8.50; 8.00; 8.50], [8.50; 9.50; 8.00; 10.00; 9.00])

let (a, b) = timesWorked

let week1 = [for t in a do yield t]
let week2 = [for t in b do yield t]

printfn "Work 1 time worked: %A\tTotal: %0.02f" week1 (List.sum week1)
printfn "Work 2 time worked: %A\tTotal: %0.02f" week2 (List.sum week2)

This would produce:

Work 1 time worked: [8.0; 9.0; 8.5; 8.0; 8.5]   Total: 42.00
Work 2 time worked: [8.5; 9.5; 8.0; 10.0; 9.0]  Total: 45.00
Press any key to close this window . . .

The Average of a List

The List module supports various arithmetic operations on a list if the elements on that list are numbers.

The List.average() function is used to calculate the average of numbers. Here is an example:

type EmploymentStatus =
    | Unknown  = 0
    | FullTime = 1
    | PartTime = 2
    | Intern   = 3
    | Seasonal = 4
     
type Employee(emplNbr, status, salary) =
    member this.EmployeeNumber = emplNbr
    member this.EmploymentStatus : EmploymentStatus = status
    member this.YearlySalary = salary
 
let employees = [ Employee("9749-8075", EmploymentStatus.FullTime, 60000.00); Employee("2038-4051", EmploymentStatus.FullTime, 82000.00);
                  Employee("2405-8296", EmploymentStatus.Seasonal, 35400.00); Employee("2813-3044", EmploymentStatus.PartTime, 25500.00);
                  Employee("5031-9259", EmploymentStatus.FullTime, 25500.00); Employee("7092-3094", EmploymentStatus.FullTime, 104000.00); ]
 
let salaries = [ for empl in employees -> empl.YearlySalary ]
let avgSalary = List.average salaries
printfn "Salaries: %A" salaries;
printfn "Average Salary: %0.0f" avgSalary;

This would produce:

Salaries: [60000.0; 82000.0; 35400.0; 25500.0; 25500.0; 104000.0]
Average Salary: 55400
Press any key to close this window . . .

Sorting Items

Introduction

Sorting the items of a list consists of re-arranging them in order. If the items are of a primitive type, you can arrange them in alphabetical, numerical, or chronological order. If the items are based on a class, you must implement the IComparable interface that is equipped with a method named CompareTo.

To let you arrange the items of a list, the List module is equipped with a function named sort. Its signature is:

List.sort : 'T list -> 'T list

Here is an example:

open System;
 
type EmploymentStatus =
    | Unknown  = 0
    | FullTime = 1
    | PartTime = 2
    | Intern   = 3
    | Seasonal = 4
     
type Employee(emplNbr, status, salary) =
    member this.EmployeeNumber = emplNbr
    member this.EmploymentStatus : EmploymentStatus = status
    member this.YearlySalary = salary
    interface IComparable with
        member this.CompareTo(obj : Object) =
            match obj with
            | :? Employee as empl -> compare this.YearlySalary empl.YearlySalary
            | _ -> 0
 
let employees = [ Employee("9749-8075", EmploymentStatus.FullTime, 60000.00); Employee("2038-4051", EmploymentStatus.FullTime, 82000.00);
                  Employee("2405-8296", EmploymentStatus.Seasonal, 35400.00); Employee("2813-3044", EmploymentStatus.PartTime, 32500.00);
                  Employee("5031-9259", EmploymentStatus.FullTime, 55000.00); Employee("7092-3094", EmploymentStatus.FullTime, 104000.00); ]
 
let sorted = List.sort employees
 
printfn "Employees Salary Summary"
printfn "==================================="
printfn "           Employment \tYearly"
printfn "Empl #      Status\tSalary"
printfn "-----------------------------------"
List.iter (fun (empl : Employee) -> printfn "%s  %A\t%0.0f" empl.EmployeeNumber empl.EmploymentStatus empl.YearlySalary) sorted

Sorting Items By a Condition

The List.sort() function is used to simply arrange all records of a list. If you want to apply a condition by which to sort records, you can use the sortBy() function of the List module. Its signature is:

List.sortBy : ('T -> 'Key) -> 'T list -> 'T list

This function takes two arguments. The first arguments specifies a condition by which to sort. Only the items that respond to the condition are sorted. The other items in their original positions. Here is an example:

type EmploymentStatus =
    | Unknown  = 0
    | FullTime = 1
    | PartTime = 2
    | Intern   = 3
    | Seasonal = 4
     
type Employee(emplNbr, status, salary) =
    member this.EmployeeNumber = emplNbr
    member this.EmploymentStatus : EmploymentStatus = status
    member this.YearlySalary = salary
 
let employees = [ Employee("9749-8075", EmploymentStatus.FullTime, 60000.00);  Employee("2038-4051", EmploymentStatus.FullTime, 82000.00);
                  Employee("7092-3094", EmploymentStatus.FullTime, 104000.00); Employee("2813-3044", EmploymentStatus.PartTime, 25500.00);
                  Employee("2405-8296", EmploymentStatus.Seasonal, 35400.00);  Employee("5031-9259", EmploymentStatus.FullTime, 18500.00);  ]
 
let sorted = List.sortBy (fun (empl : Employee) -> empl.YearlySalary >= 60000.00) employees

printfn "Employees Records - Before Sorting"
printfn "==================================="
printfn "           Employment \tYearly"
printfn "Empl #      Status\tSalary"
printfn "-----------------------------------"
List.iter (fun (empl : Employee) -> printfn "%s  %A\t%0.0f" empl.EmployeeNumber empl.EmploymentStatus empl.YearlySalary) employees
printfn "-----------------------------------"
 
printfn "Employees Records - Sorting Employees Whose Salary is >= 60,000"
printfn "==================================="
printfn "           Employment \tYearly"
printfn "Empl #      Status\tSalary"
printfn "-----------------------------------"
List.iter (fun (empl : Employee) -> printfn "%s  %A\t%0.0f" empl.EmployeeNumber empl.EmploymentStatus empl.YearlySalary) sorted
printfn "-----------------------------------"

This would produce

Employees Records - Before Sorting
===================================
           Employment   Yearly
Empl #      Status      Salary
-----------------------------------
9749-8075  FullTime     60000
2038-4051  FullTime     82000
7092-3094  FullTime     104000
2813-3044  PartTime     25500
2405-8296  Seasonal     35400
5031-9259  FullTime     18500
-----------------------------------
Employees Records - Sorting Employees Whose Salary is >= 60,000
===================================
           Employment   Yearly
Empl #      Status      Salary
-----------------------------------
2813-3044  PartTime     25500
2405-8296  Seasonal     35400
5031-9259  FullTime     18500
9749-8075  FullTime     60000
2038-4051  FullTime     82000
7092-3094  FullTime     104000
-----------------------------------
Press any key to close this window . . .

Previous Copyright © 2014-2024, FunctionX Monday 06 November 2023 Next