Fsharp: Dictionary
ai generated
F# Hashtable and Dictionary Tutorial
F# provides powerful key-value data structures for fast lookups. The two main options are:
System.Collections.Generic.Dictionary<'Key, 'Value>— The modern, generic, and recommended choice.System.Collections.Hashtable— The older, non-generic version (stores everything asobj).
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:
- Boxes value types (performance hit).
- Not type-safe (runtime casts needed).
- Slower for most modern scenarios.
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
- Capacity: Always set initial capacity when you know approximate size to avoid resizing.
- Custom equality: Use
Dictionary<'Key, 'Value>(IEqualityComparer<'Key>)for custom key comparison. - ConcurrentDictionary: Use
System.Collections.Concurrent.ConcurrentDictionaryfor multi-threaded scenarios. - Read-only view:
d :> IReadOnlyDictionary<_,_>or thedictkeyword.
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.