F# Map
last modified May 1, 2025
This article explores how to effectively work with the Map
collection in F#.
A map in F# is an immutable collection of key/value pairs, designed for efficient lookups and data association. Unlike lists or arrays, maps provide fast access to values using unique keys, making them ideal for structured data storage. Since maps are immutable, any modifications create a new map instance rather than altering the existing one, ensuring consistency and functional purity.
Maps maintain their keys in sorted order, offering predictable iteration behavior and optimized retrieval performance. They are commonly used for associative data structures, such as configuration settings, lookup tables, or structured collections requiring fast key-based access.
F# Map simple example
The following is a simple map example.
let words = Map [1, "book"; 2, "sky"; 3, "work"; 4, "cloud"] printfn "%A" words printfn "%s" words[1] printfn "%s" words[4]
We have a map of words. The keys are integers and the values are strings.
let words = Map [1, "book"; 2, "sky"; 3, "work"; 4, "cloud"]
The keys are separated from values with a comma character. The pairs are separated with a semicolon.
printfn "%A" words
With the %A
format specifier, we pretty-print the map.
printfn "%s" words[1] printfn "%s" words[4]
We print the elements with index 1 and 4.
λ dotnet fsi main.fsx map [(1, "book"); (2, "sky"); (3, "work"); (4, "cloud")] book cloud
F# Map size
The Count
property returns the number of pairs in the map.
let words = Map [1, "book"; 2, "sky"; 3, "work"; 4, "cloud"] let n = words.Count printfn $"The map has {n} elements"
The example prints the number of elements int he map.
F# Map iteration
In the next example, we loop over the elements of a Map.
let words = Map [1, "book"; 2, "sky"; 3, "work"; 4, "cloud"] printfn "%A" words words |> Map.iter (fun k v -> printfn ($"{k}: {v}")) for key in words.Keys do printfn "%d" key for value in words.Values do printfn "%s" value for e in words do printfn $"{e.Key}: {e.Value}"
We provide two basic ways of iteration: functional and imperative. The
functional uses the Map.iter
function, while the imperative uses
for loops.
words |> Map.iter (fun k v -> printfn ($"{k}: {v}"))
The Map.iter
is the functional way of looping over map elements.
for key in words.Keys do printfn "%d" key
We loop over the keys of the map.
for value in words.Values do printfn "%s" value
We iterate over the values of the map.
for e in words do printfn $"{e.Key}: {e.Value}"
We iterate over the pairs of the map.
λ dotnet fsi main.fsx map [(1, "book"); (2, "sky"); (3, "work"); (4, "cloud")] 1: book 2: sky 3: work 4: cloud 1 2 3 4 book sky work cloud 1: book 2: sky 3: work 4: cloud
F# Map.filter
We can filter map elements with Map.filter
.
let words = Map [ 1, "book" 2, "sky" 3, "work" 4, "cloud" 5, "water" 6, "war" ] words |> Map.filter (fun _ v -> v.Contains "w") |> Map.values |> Seq.iter (printfn "%s")
In the program, we find out all values which start with 'w'.
words |> Map.filter (fun _ v -> v.Contains "w") |> Map.values |> Seq.iter (printfn "%s")
We pass a predicate lambda to the filter method; it checks if the value
contains 'w'. The result is passed to the Map.values
to extract
all values. Then the values are iterated and printed to the console.
λ dotnet fsi main.fsx work water war
F# Map Remove
The Remove
method returns a new map from which the specified pair
is removed.
let words = Map [ 1, "book" 2, "sky" 3, "work" 4, "cloud" 5, "water" 6, "war" ] let res = words.Remove 1 printfn "%A" res printfn "%A" words
In the example, we remove the element with key 1. The original map is not changed.
λ dotnet fsi main.fsx map [(2, "sky"); (3, "work"); ... (6, "war")] map [(1, "book"); (2, "sky"); (3, "work"); ... (6, "war")]
F# Map Add
With Add
, we add a new element to the map.
let words = Map [ 1, "book" 2, "sky" 3, "work" 4, "cloud" 5, "water" 6, "war" ] let res = Map.add 7 "falcon" words printfn "%A" res printfn "%A" words
We add a new pair to the map.
λ dotnet fsi main.fsx map [(1, "book"); (2, "sky"); ... (6, "war"); (7, "falcon")] map [(1, "book"); (2, "sky"); ... (6, "war")]
F# Map.empty
We can create an empty map with Map.empty
and add new elements
with Add
.
type User = { Name: string Occupation: string } let users = Map.empty. Add(1, {Name="John Doe"; Occupation="gardener"}). Add(2, {Name="Roger Roe"; Occupation="driver"}). Add(3, {Name="Lucy Smith"; Occupation="teacher"}). Add(4, {Name="Tom Jones"; Occupation="programmer"}) users |> Map.iter (fun k v -> printfn $"{k}: {v}")
Utilizing Map.empty
, we create a map of users.
λ dotnet fsi main.fsx 1: { Name = "John Doe" Occupation = "gardener" } 2: { Name = "Roger Roe" Occupation = "driver" } 3: { Name = "Lucy Smith" Occupation = "teacher" } 4: { Name = "Tom Jones" Occupation = "programmer" }
F# list of maps
In the next example, we define a list of maps.
let fruits1 = Map [ "oranges", 2; "bananas", 3 ] let fruits2 = Map [ "plums", 4; "kiwis", 5 ] let all = [ Map[1, fruits1]; Map[2, fruits2] ] all |> List.iter (Map.iter (fun k v -> printfn $"{k} {v}")) printfn "-------------------" for nested in all do for e in nested do printfn $"{e.Key} {e.Value}"
We define two maps and insert them into a list. The list is then iterated in declarative and imperative way.
all |> List.iter (Map.iter (fun k v -> printfn $"{k} {v}"))
We iterate of the list of maps declaratively using List.iter
and
Map.iter
.
for nested in all do for e in nested do printfn $"{e.Key} {e.Value}"
Imperatively, we loop over the list using two for loops.
λ dotnet fsi main.fsx 1 map [(bananas, 3); (oranges, 2)] 2 map [(kiwis, 5); (plums, 4)] ------------------- 1 map [(bananas, 3); (oranges, 2)] 2 map [(kiwis, 5); (plums, 4)]
In this article we have worked with maps in F#.