F# For Dummys - Day 16 Collections Sequence

75 阅读2分钟

Today we learn Sequence, represents an ordered, read-only series of elements

Why Sequence

  • Sequences are particularly useful when you have a large, ordered collection of data but do not necessarily expect to use all of the elements.
  • Individual sequence elements are computed on-demand, so a sequence can provide better performance than a list in situations in which not all the elements are used

What is computed on-demand
like buying a burger in KFC, the staff prepared 1000 burgers in the early morning, so you got your burger immediately, all the burgers are made before customer order, this is called eager evaluation

then you ordered a fried chicken, the staff replies: sorry, you have to wait for a minute, as we need to fry the chicken first, they only do the work when some ordered, this is called lazy evaluation, also known as On-demand computation

Create Sequence

  • Explicitly specifying elements
let seq1 = seq [1; 2; 3; 4]
printfn "seq: %A" seq1
  • Using range expression
let seq1 = seq { 1 .. 10 } // from 1 to 10
printfn "seq: %A" seq1 // seq: seq [1; 2; 3; 4; ...]

use step in range expression

let seq1 = seq { 1 .. 2 .. 10 } // start from 1, add 2 each time
printfn "seq: %A" seq1 // seq: seq [1; 3; 5; 7; ...]
  • Using for loop
let seq1 = seq { for i in 1 .. 10 -> i }
printfn "seq: %A" seq1
  • ofList
    Views the given list as a sequence
let inputs = [ 1; 2; 5 ]
let seq1 = inputs |> Seq.ofList
printfn "seq: %A" seq1
  • ofArray
let inputs = [| 1; 2; 5 |]
let seq1 = inputs |> Seq.ofArray
printfn "seq: %A" seq1
  • Seq.initInfinite generate an infinite sequence
let infiniteSeq = Seq.initInfinite (fun i -> i * 2)
printfn "infiniteSeq %A" infiniteSeq

define a start for infinite sequence

let start = 5
let infiniteSeq = Seq.initInfinite (fun i -> i + start)
printfn "infiniteSeq %A" infiniteSeq // infiniteSeq seq [5; 6; 7; 8; ...]

or define a start like this

let infiniteSeq = Seq.initInfinite ((+) 5)
printfn "infiniteSeq %A" infiniteSeq // infiniteSeq seq [5; 6; 7; 8; ...]

Loop Sequence

  • for loop
let numbers = seq { 1 .. 10 }

for number in numbers do
    printfn "Number: %d" number
  • Seq.iter
let numbers = seq { 1 .. 10 }

Seq.iter (fun x -> printfn "Number: %d" x) numbers

Access element

  • Seq.item syntax: Seq.item index source, thrown ArgumentException when the index is negative or the input sequence does not contain enough elements
let numbers = seq { 1 .. 10 }
let thirdElement = Seq.item 2 numbers  // Indexing is zero-based

printfn "The third element is %d" thirdElement
  • Seq.head && Seq.tail
    Seq.head: Returns the first element of the sequence
    Seq.tail: Returns a sequence that skips 1 element of the underlying sequence and then yields the remaining elements of the sequence
let numbers = seq { 1 .. 10 }
let firstElement = Seq.head numbers
let restElement = Seq.tail numbers

printfn "The first element is %d" firstElement // The first element is 1
printfn "The rest element is %A" restElement // The rest element is seq [2; 3; 4; 5; ...]

Operate element

  • Seq.updateAt
    Return a new sequence with the item at a given index set to the new value
    syntax: Seq.updateAt index value source
let newSeq = Seq.updateAt 1 9 seq { 0; 1; 2 }
// let newSeq = Seq.updateAt 1 9 (seq { 0; 1; 2 })
printfn "newSeq: %A" newSeq // newSeq: seq [0; 9; 2]
  • Seq.filter
    Returns a new collection containing only the elements of the collection for which the given predicate returns "true". This is a synonym for Seq.where
    syntax: Seq.filter predicateFunc sourceSeq
let numbers = seq { 1 .. 10 }
let evenNumbers = Seq.filter (fun x -> x % 2 = 0) numbers

Seq.iter (fun x -> printfn "Even Number: %d" x) evenNumbers
  • Seq.map
    Builds a new collection whose elements are the results of applying the given function to each of the elements of the collection
    syntax: Seq.filter mappingFunc sourceSeq
let numbers = seq { 1 .. 10 }
let doubleNumbers = Seq.map (fun x -> x * 2) numbers

Seq.iter (fun x -> printfn "doubleNumbers: %d" x) doubleNumbers
  • Seq.fold
    Applies a function to each element of the collection syntax: Seq.fold folderFunc state sourceSeq
type Charge =
     | In of int
     | Out of int
let inputs = [In 1; Out 2; In 3]
let balance = Seq.fold (fun acc charge ->
    match charge with
    | In i -> acc + i
    | Out o -> acc - o) 0 inputs

printfn "balance %A" balance // balance 2

or use pipeline operator to pass state sourceSeq, here is ||> for passing more than one param

type Charge =
     | In of int
     | Out of int
let inputs = [In 1; Out 2; In 3]
let balance = (0, inputs) ||> Seq.fold (fun acc charge ->
    match charge with
    | In i -> acc + i
    | Out o -> acc - o)

printfn "balance %A" balance // balance 2