Fsharp: Dictionary

By Xah Lee. Date: .
xtodo

ai generated

F# Hashtable and Dictionary Tutorial

F# provides powerful key-value data structures for fast lookups. The two main options are:

Recommendation: Always prefer Dictionary unless you have a specific reason to use Hashtable (e.g., legacy interop).

1. Opening Namespaces

open System.Collections.Generic

2. Creating a Dictionary

Empty Dictionary

let dict1 = Dictionary<int, string>()                    // mutable
let dict2 = Dictionary<string, int>(capacity = 100)     // with initial capacity (performance)

From sequence of tuples (F# idiomatic)

let dict3 = dict [ (1, "one"); (2, "two"); (3, "three") ]   // immutable IDictionary (read-only view)

From existing collection

let numbers = [ (1, "one"); (2, "two") ]
let d = Dictionary.ofSeq numbers

3. Adding and Updating Items

let d = Dictionary<string, int>()

d.Add("apple", 5)                    // throws if key exists
d.["banana"] <- 10                   // indexer: adds or updates (preferred)
d["cherry"] <- 7

// Safe add
if not (d.ContainsKey "apple") then
    d.Add("apple", 99)

4. Accessing Values

// Direct access (throws KeyNotFoundException if missing)
let count = d["banana"]

// Safe access
match d.TryGetValue "apple" with
| true, v  -> printfn "Found: %d" v
| false, _ -> printfn "Not found"

// Using ContainsKey
if d.ContainsKey "banana" then
    printfn "%d" d["banana"]

5. Removing Items

d.Remove "apple" |> ignore          // returns true if removed
d.Remove "nonexistent"              // returns false, no exception

6. Iterating Over a Dictionary

// Over key-value pairs
for kvp in d do
    printfn "%s -> %d" kvp.Key kvp.Value

// Keys only
for k in d.Keys do
    printfn "Key: %s" k

// Values only
for v in d.Values do
    printfn "Value: %d" v

// Functional style
d |> Seq.iter (fun kvp -> printfn "%s = %d" kvp.Key kvp.Value)

7. Common Operations

let size = d.Count
d.Clear()

// Copy to array
let arr = d |> Seq.toArray

// Convert to F# Map (immutable)
let mapVersion = d |> Map.ofSeq

8. Dictionary vs F# Map

Feature Dictionary Map (F# built-in)
Mutability Mutable Immutable
Performance Faster for large mutations Good for small/functional
Thread safety Not thread-safe Safe (immutable)
Typical use High-performance mutable data Functional pipelines

9. Hashtable Example (Legacy)

open System.Collections

let ht = Hashtable()
ht.Add("one", 1)
ht.Add(2, "two")          // mixed types allowed

// Access
let v = ht["one"] :?> int

// Usually avoid unless you need non-generic behavior

Hashtable drawbacks:

10. Practical Example: Word Counter

let wordCount (text: string) =
    let d = Dictionary<string, int>()
    for word in text.ToLower().Split([|' '; '\n'; '\t'|], System.StringSplitOptions.RemoveEmptyEntries) do
        if d.ContainsKey word then
            d[word] <- d[word] + 1
        else
            d[word] <- 1
    d

let sample = "The quick brown fox jumps over the lazy dog"
let counts = wordCount sample

counts |> Seq.iter (fun kvp -> printfn "%s: %d" kvp.Key kvp.Value)

11. Advanced Tips

Summary Cheat Sheet

// Creation
let d = Dictionary<int, string>()
let d2 = dict [1, "a"; 2, "b"]

// Add / Update
d["key"] <- value
d.Add(key, value)

// Read
d[key]
d.TryGetValue key

// Remove / Clear
d.Remove key
d.Clear()

// Iterate
for KeyValue(k, v) in d do ...     // nice pattern matching

This covers 95% of real-world usage. Dictionary is fast, flexible, and integrates beautifully with both OO and functional F# code.

Happy coding! If you want examples with custom comparers, performance benchmarks, or integration with records/unions, just ask.

Fsharp, String