HomeSearch

F# List Examples, String Lists

Store collections of strings and ints with lists. Use a for-loop upon a list.
List. There are many animals. In nature we find cats, birds, fish. In a list we can store strings of many animals. We can make lists of any types.
Head and tail. When we create a list, it cannot be changed. It is immutable. But by accessing the Head and Tail, we can keep track of which elements we have processed.
For-loop. Let us create a list of 4 strings. Please note that the semicolon is used to separate elements in the list. A comma will create tuples within the list.

For: We use a for-in, do-loop to access all the elements in the list. Each "animal" is a string. We use printfn to print these values.

F# program that uses string list // Create a list of strings with animal names. let animals = ["cat"; "bird"; "fish"; "fox"] // Use loop to print all animals. for animal in animals do printfn "%A" animal Output "cat" "bird" "fish" "fox"
Length, Head, Tail. Again we create an example string list. We access the Length of the list, which is 3. We then use the Head and Tail properties, which are important on the list.

Head: This is the first element within the list. It is not a list itself. It is just an element.

Tail: This is another list, but it does not include the first element. It is the remainder of the list.

F# program that uses Length, Head, Tail // Create a list of strings with animal names. // ... Use semicolon to separate elements, not comma. let continents = ["Antarctica"; "Asia"; "Africa"] // It has three elements. let count = continents.Length printfn "%A" count // Head is the first element (a string here). let head = continents.Head printfn "%A" head // Tail is the list except for the first element. // ... It includes the second element onwards. let tail = continents.Tail printfn "%A" tail Output 3 "Antarctica" ["Asia"; "Africa"]
Recursion, match. This is a more complex example. We introduce a recursive method printExample. The rec keyword indicates it is a recursive (self-calling) method.

Match: This block must handle all cases of the list when evaluated. The list can be empty, or have a head and a tail.

Head, tail: This case in the match-with statement handles a nonempty list. It prints the head and then recurses on the tail.

So: We repeatedly call the method with the tail as the argument. The tail keeps shrinking. The head is printed each time.

F# program that uses recursion, match on list // Use recursion to print a list. // ... Match handles all cases of the list. // We handle the head and tail by printing the head. // We use recursion on the tail for the next elements. let rec printExample list = match list with | [] -> () | head :: tail -> printf "%d " head printExample tail // Test our recursive method. let numbers = [5; 10; 15; 20] printExample numbers Output 5 10 15 20
List.append. An F# list cannot be appended to in-place. Instead, we can use List.append to combine two lists together into a third list.

Tip: To use List.append, we must have two lists. But we can create a one-element list to append just one element.

F# program that appends lists let colors1 = ["blue"; "orange"] // Combine the two lists. // ... We append a 1-element list to append an element. let colors2 = List.append colors1 ["pink"] // Display before and after lists. printfn "%A" colors1 printfn "%A" colors2 Output ["blue"; "orange"] ["blue"; "orange"; "pink"]
Concatenate operator. With the "@" symbol we concatenate (combine) two lists. This is the same as the List.append function, but with shorter syntax.

Here: We add an element at the start, and then add one at the end of the list. A new list is created each time.

F# program that uses concatenate operator let materials = ["plastic"; "wood"] printfn "%A" materials // Add element to the beginning of the list. let materials2 = ["cement"] @ materials printfn "%A" materials2 // Add element to the end of the list. let materials3 = materials2 @ ["brick"] printfn "%A" materials3 Output ["plastic"; "wood"] ["cement"; "plastic"; "wood"] ["cement"; "plastic"; "wood"; "brick"]
Add to front. With two ":" characters we add to the front of a list. This is a clearer syntax than using "@" or List.append for this operation.
F# program that adds to front // Create a list with two elements. let lengths = [10; 10] printfn "%A" lengths // Add a value to the front. let lengths2 = 5 :: lengths printfn "%A" lengths2 // Add a new front. let lengths3 = 0 :: lengths2 printfn "%A" lengths3 Output [10; 10] [5; 10; 10] [0; 5; 10; 10]
Argument, map, sort. This example is more complex. It introduces a sortDouble function that receives a list argument. It then pipelines that list through List.map and List.sort.

Note: In sortDouble we receive an argument of name "x." We pass this list argument to List.map.

List.map: This uses a lambda expression, specified with "fun," to double each element (with identifier "y").

List.sort: This is called after List.map with that function's result. This sorts the doubled list in an ascending order (low to high).

Sort
F# program that uses list argument, map, sort // This function doubles all elements in a list. // ... It then sorts them. let sortDouble x = x |> List.map (fun y -> y * 2) |> List.sort let items = [20; 10; 5; 50] // Double and sort our list elements. let result = sortDouble items printfn "%A" result Output [10; 20; 40; 100]
ResizeArray. With F# we can access all .NET types. The System.Collections.Generic.List is often used. And F# provides a handy alias for it called ResizeArray.

Note: The ResizeArray underscore means a type is chosen automatically. We use Seq.toList to convert to an F# list.

Seq
F# program that uses ResizeArray // Create a System.Collections.Generic.List. // ... The ResizeArray is an aliased type. let resize = new ResizeArray<_>() resize.Add(300) resize.Add(600) resize.Add(0) // Convert our ResizeArray to a list. let result = Seq.toList resize // Display our list. printfn "%A" result.Length printfn "%A" result.Head Output 3 300
Some notes. Imagine a method acts on the first element of a list, and then must process the remainder of the list in later calls. We can just process Head, and use Tail to eliminate Head.

So: With Head and Tail we can reduce the list as we use it. This keeps track of our position within the list.

A review. With lists, we collect elements into groups. We can use higher-order procedures to act upon these lists. And Head and Tail help us reduce lists as we proceed.
© 2007-2019 Sam Allen. Every person is special and unique. Send bug reports to info@dotnetperls.com.
Home
Dot Net Perls