Arrays and Sequences
Prerequisites: Lists
Arrays
An array is a fixed-size, mutable block of values with fast
access by index. Write it with [| ... |]:
let scores = [| 70; 85; 92 |]
printfn "%d" scores[1]
printfn "%d" scores.Length
scores[1] <- 88
printfn "%A" scores
let zeros = Array.zeroCreate<int> 4
let filled = Array.create 3 "x"
let table = Array.init 5 (fun i -> i * 10)
printfn "%A %A %A" zeros filled table
printfn "%A" scores[0..1]
85
3
[|70; 88; 92|]
[|0; 0; 0; 0|] [|"x"; "x"; "x"|] [|0; 10; 20; 30; 40|]
[|70; 88|]
Arrays are the same as .NET arrays (int[] in C#), so they're what
you pass to and receive from most .NET APIs. Use them when you need
random access or top performance on large data.
Sequences
A sequence (seq<'T>) is a lazy series of values: items are
computed only when something asks for them. That means a sequence can
even be infinite:
let naturals = Seq.initInfinite (fun i -> i + 1)
naturals
|> Seq.filter (fun n -> n % 7 = 0)
|> Seq.take 5
|> Seq.toList
|> printfn "%A"
let lazyNumbers =
seq {
for i in 1 .. 3 do
printfn "computing %d" i
yield i * 100
}
printfn "defined, nothing computed yet"
for n in lazyNumbers do
printfn "got %d" n
[7; 14; 21; 28; 35]
defined, nothing computed yet
computing 1
got 100
computing 2
got 200
computing 3
got 300
Notice that "computing" and "got" alternate: each item is produced just
before it's used. seq<'T> is .NET's IEnumerable<T>, so every .NET
collection is also a sequence.
Converting between them
let list = [3; 1; 2]
let array = List.toArray list
let backToList = Array.toList array
let fromSeq = seq { 1 .. 3 } |> Seq.toList
printfn "%A %A %A %A" list array backToList fromSeq
printfn "%A" (List.ofSeq "abc")
[3; 1; 2] [|3; 1; 2|] [3; 1; 2] [1; 2; 3]
['a'; 'b'; 'c']
Which one should I use?
| Use | When |
|---|---|
list |
the default for F# code: immutable, pattern-matchable, small to medium size |
array |
random access, large data, performance, .NET interop |
seq |
lazy or infinite data, streaming files, or "any collection" parameters |
The List, Array, and Seq modules have almost the same functions
(map, filter, sum, ...), so switching is easy.