Mutable .NET Collections
Prerequisites: Maps and sets
F#'s own collections are immutable. For performance-critical code, or
when talking to .NET APIs, you'll also use the mutable collections from
System.Collections.Generic.
ResizeArray
ResizeArray<'T> is F#'s name for .NET's List<T> — a growable array
(not to be confused with the F# immutable list):
let items = ResizeArray<string>()
items.Add "apple"
items.Add "banana"
items.AddRange [ "cherry"; "date" ]
items.Remove "banana" |> ignore
items.Insert(0, "avocado")
printfn "%d items: %s" items.Count (String.concat ", " items)
printfn "%s" items[1]
let lengths = items |> Seq.map _.Length |> List.ofSeq
printfn "%A" lengths
4 items: avocado, apple, cherry, date
apple
[7; 5; 6; 4]
Dictionary
open System.Collections.Generic
let stock = Dictionary<string, int>()
stock["apples"] <- 10
stock["pears"] <- 4
stock["apples"] <- stock["apples"] - 3
printfn "%d" stock["apples"]
match stock.TryGetValue "plums" with
| true, n -> printfn "plums: %d" n
| false, _ -> printfn "no plums"
for KeyValue (fruit, count) in stock do
printfn "%s=%d" fruit count
let readOnly = dict [ "a", 1; "b", 2 ]
printfn "%d" readOnly["b"]
7
no plums
apples=7
pears=4
2
dict builds a read-only dictionary from pairs — quick lookup tables
without mutation.
HashSet
open System.Collections.Generic
let seen = HashSet<string>()
for word in "the cat saw the other cat".Split ' ' do
if not (seen.Add word) then
printfn "duplicate: %s" word
printfn "%d unique" seen.Count
duplicate: the
duplicate: cat
4 unique
Add returns false when the item was already present.
Immutable or mutable?
| Need | Choose |
|---|---|
| Default choice, sharing data safely | list, Map, Set |
| Many lookups or inserts in a hot loop | Dictionary, HashSet |
| Building up a large collection step by step | ResizeArray, then Seq.toList if needed |
| Passing data to .NET APIs | whatever the API expects (List<T>, arrays) |
A good pattern is to use a mutable collection inside a function for
speed and return an immutable result, so callers never see the
mutation. Note that Dictionary and ResizeArray are not
thread-safe; use System.Collections.Concurrent types when several
threads write.