F # 10: Lists

Any serious programming in any language will always include lists. Thus, you will be pleased to know that F # supports lists very, very well with its List module. A list in F # is an ordered, unchanging series of elements of the same type.



Create a list



There are several ways in F # that you can create a list.





let prettyPrint desc list = printfn desc printfn "%A" list //empty list let listEmpty = [] //simple list let list1 = [1 .. 10 ] //simple list, with step value let list2 = [1 ..2..10 ] //using for loops to create lists let list3 = [for i in 1 .. 10 -> i*2 ] prettyPrint "let listEmpty = []" listEmpty prettyPrint "let list1 = [ 1 .. 10 ]" list1 prettyPrint "let list2 = [ 1 .. 2..10 ]" list2 prettyPrint "[ for i in 1 .. 10 -> i*2 ]" list3
      
      





image



The last example shown above shows how to use the for loop to create a list, which is very cool, but there is something even more cool and powerful in the F # toolkit, namely List Comprehensions.



List Comprehensions is a powerful method that allows you to create lists using pretty much the standard F #, which includes functions / loops / conditions, etc.



Let's continue to look at an example of how we could create lists.



 let is2 x = match x with | 2 -> "YES" | _ -> "NO" //yield directly let list1 = [ yield 1; yield 2; yield 3; ] //yield numbers between 1 and 20 where we use the //Math.Pow function to return a new number let list2 = [for i in 1.0 .. 20.0 do yield Math.Pow(i,2.0) ] //yield only numbers between 1 and 20 that //can be divided by 5 let list3 = [ for i in 1 .. 20 do if i % 5 = 0 then yield i ] //yields YES/NO strings depending on //whether source int = 2 or not let list4 = [for i in 1 .. 5 -> is2 i ]
      
      





image



Some useful list operators



Cons operator



We can use the cons operator “::” to add values ​​to an existing list, so suppose we had this list:



 let list1 = [1;2;3;4] let list2 = 42 :: list1
      
      





image



Concatenation operator



Another very useful operator is the "@" operator, which allows you to combine lists of the same type. So, for example, if we had this:



 let list1 = [1;2;3;4] let list2 = [5;6;7;8] let list3 = list1 @ list2
      
      





image



List Module



I don’t think I overdo it when I say that the List module is a key module in F #. In fact, the MSDN documentation for it is very good compared to others in F #. Therefore, I don’t think I can add a lot of usefulness to the examples found on MSDN, but I will give here a few for your convenience, but you should study MSDN for more information .



The properties



Head

'T





First element

Empty

'T list





Returns an empty list of the specified type

Isempty

bool

true - if there are no elements in the list

Item

'T

An item that is at a specific index

Length

int

Amount of elements

Tail

'T list

List without first item:



 let list1 = [ 1; 2; 3 ] // Properties printfn "list1.IsEmpty is %b" (list1.IsEmpty) printfn "list1.Length is %d" (list1.Length) printfn "list1.Head is %d" (list1.Head) printfn "list1.Tail.Head is %d" (list1.Tail.Head) printfn "list1.Tail.Tail.Head is %d" (list1.Tail.Tail.Head) printfn "list1.Item(1) is %d" (list1.Item(1))
      
      





image



Filter



Returns a new collection containing only the elements of the collection for which the given predicate returns true. Here is a trivial example that selects only even numbers from a list to create a new list



 let evenOnlyList = List.filter (fun x -> x % 2 = 0) [1; 2; 3; 4; 5; 6]
      
      





image



Search (find)



Returns the first element for which this function returns true. In this example, since the list from 1 to 100 contains 5, 5 is the 1st number, which is divided by 5, so this is the return value:



image



For all (forall)



Checks if all elements in the collection satisfy a given predicate. In this example, the entire list must contain 0 in order to get a true return value.



 let isAllZeroes list = List.forall (fun elem -> elem = 0.0) list printfn "%b" (isAllZeroes [0.0; 0.0]) printfn "%b" (isAllZeroes [0.0; 1.0])
      
      





image



Apply to all (Iteri)



Applies this function to each item in the collection. The integer passed to the function indicates the index of the element.



 let data = ["Cats";"Dogs";"Mice";"Elephants"] data |> List.iteri (fun ix -> printfn "item %d: %s" ix)
      
      





image



Sort by (SortWith)



Sorts the specified list using this comparison function.



 let list1 = [ ""; "&"; "&&"; "&&&"; ""; "|"; "||"; "|||" ] printfn "Before sorting: " list1 |> printfn "%A" //custom sorting function let sortFunction (string1:string) (string2:string) = if (string1.Length > string2.Length) then 1 else if (string1.Length printfn "After sorting:\n%A"
      
      





image



There are many useful functions in the list module, this is just a small part of what you can find.



A small look at recursion over lists



No discussion of lists would be complete without talking about recursion. Recursion is what the whole post will be dedicated to, but for now, let's take a look at what it takes to write a recursive function that works on a list in F #.



 let printIt desc x = printfn "%A %A" desc x let rec printList list = match list with | h :: t -> printIt "head=" h printIt "tail=" t printList t | [] -> () printList [1;2;3;4;5]
      
      





Note the use of the rec keyword, which tells the F # compiler that this function will be recursive. Without this keyword, a recursive function call - you will receive a compilation error message, although with a not very clear error text.



image



So, let's see the results of the example shown a little higher with the following list [1; 2; 3; four; 5]



image



You can see that everything works just fine, and it stops working when the value matches an empty list, as expected.



All Articles