F# For Dummys - Day 12 Collections List

75 阅读3分钟

Today we learn List, an immutable, ordered collection of elements of the same type
The term "ordered" here means that the list maintains the sequence in which elements were added, didn't mean List is sorted

Create List

  • Explicitly specifying elements
let numbers = [1; 2; 3; 4; 5]
let names = ["Alice"; "Bob"; "Charlie"]

the ; could be omit between elements if you write them in seperated lines

let list123 = [ 1 // first comment
                2 // second comment
                3 // third comment
                ]

all elements should be the same type

let list123 = ["1"; 2; 3]

the first elements is string, the rest is int, will get compile error:
All elements of a list must be implicitly convertible to the type of the first element, which here is 'string'. This element has type 'int'.(1,21)

  • Using a range
let numbers = [1..5] // Equivalent to [1; 2; 3; 4; 5]
let evenNumbers = [2..2..10] // Equivalent to [2; 4; 6; 8; 10]
  • Using list comprehensions
let doubles = [for x in 1..5 -> x * 2] // Equivalent to [2; 4; 6; 8; 10]
let doubles = [for x in 2..2..10 -> x * 2] // Equivalent to [4; 8; 12; 16; 20]

Get element of List

  • Using index
let numbers = [1; 2; 3]
let firstNumber = numbers.[0]  // first number 1
let thirdNumber = numbers.[2]  // third number 3

printfn "firstNumber %i thirdNumber %i" firstNumber thirdNumber

if you use index not exist in List, will got index out of range exception

let numbers = [1; 2; 3]
let forthNumber = numbers.[4]

printfn "forthNumber %i" forthNumber

compile error: Unhandled exception. System.ArgumentException: The index was outside the range of elements in the list
the browser environment have bug about this exception

  • Using build-in method List.item
let numbers = [1; 2; 3]
let firstNumber =  numbers |> List.item 0

printfn "firstNumber %i" firstNumber
  • head and tail
    List.head, get first element
let numbers = [1; 2; 3]
let head = numbers |> List.head

printfn "head %i" head

List.tail, return list after removing the first element, not the last element

let numbers = [1; 2; 3]
let tail = numbers |> List.tail

printfn "tail %A" tail // tail [2; 3]
printfn "numbers %A" numbers // numbers [1; 2; 3]

tail is a new List not including the first element, it won't change the value of original List numbers

Loop a List

  • for...in
let numbers = [1; 2; 3]

for number in numbers do
    printfn "Number: %d" number
  • List.iter
let numbers = [1; 2; 3]

List.iter (fun number -> printfn "Number: %d" number) numbers

fun define a lambda function here, it's equivalent to

let numbers = [1; 2; 3]
let printElement number = 
    printfn "Number: %d" number

List.iter printElement numbers

Pattern Matching with List

let numbers0 = []
let numbers1 = [1]
let numbers3 = [1; 2; 3]
let describeList lst =
    match lst with
    | [] -> "The list is empty"
    | [x] -> sprintf "The list has one element: %d" x
    | [x; y] -> sprintf "The list has two elements: %d and %d" x y
    | x :: xs -> sprintf "The list starts with %d and has more elements" x

printfn "%s" (describeList numbers0)  // The list is empty
printfn "%s" (describeList numbers1)  // The list has one element: 1
printfn "%s" (describeList numbers3)  // The list starts with %d and has more elements

Operate List

lists are indeed immutable, which means that you cannot modify a list after it has been created. Any operation that appears to modify a list (such as appending or prepending an element) actually creates a new list

  • Prepending an element
let originalList = [2; 3; 4]
let newList = 1 :: originalList

printfn "Original List: %A" originalList // Original List: [2; 3; 4]
printfn "New List: %A" newList //  New List: [1; 2; 3; 4]
  • Appending an element
let originalList = [1; 2; 3]
let newList = originalList @ [4]

printfn "Original List: %A" originalList  // Original List: [1; 2; 3]
printfn "New List: %A" newList //  New List: [1; 2; 3; 4]
  • Concatenate Lists
let originalList = [1; 2; 3]
let newList = List.append originalList [4]

printfn "Original List: %A" originalList
printfn "New List: %A" newList
  • Filter
    you can not remove an element in List directly as List is immutable, but you can filter element based on some condition, put them into a new List
let numbers = [1; 2; 3; 4; 5]
let evenNumbers = List.filter (fun x -> x % 2 = 0) numbers

printfn "evenNumbers: %A" evenNumbers // evenNumbers: [2; 4]
  • Map
    apply an operation to every elements in List, you can use loop/List comprehensions to achieve that, or use Map
let numbers = [1; 2; 3; 4; 5]
let doubleNumbers = List.map (fun x -> 2 * x) numbers

printfn "doubleNumbers: %A" doubleNumbers // doubleNumbers:  [2; 4; 6; 8; 10]
  • Fold
    "fold" or "compress" elements of List of into a single value by applying a function repeatedly
let numbers = [1; 2; 3; 4; 5]
let sum = List.fold (fun acc x -> acc + x) 0 numbers  // 15

printfn "sum: %i" sum // sum: 15

step 1: acc = 0 and x = 1 New acc = 0 + 1 = 1
step 2: acc = 1 and x = 2 New acc = 1 + 2 = 3
step 3: acc = 3 and x = 3 New acc = 3 + 3 = 6
step 4: acc = 6 and x = 4 New acc = 6 + 4 = 10
step 5: acc = 10 and x = 5 New acc = 10 + 5 = 15