F# Guide — Arrays: Fixed-Size Mutable Collections
In this tutorial, you will learn about F# Guide. We cover key concepts, practical examples, and best practices to help you master this topic.
F# arrays are fixed-size, mutable collections that provide O(1) indexed access and support all the standard functional operations like map, filter, and fold while being compatible with .NET arrays.
What You'll Learn
- Creating and initializing arrays
- Indexed access and slicing
- Array transformations
- Mutable vs immutable operations
- Performance characteristics
Why It Matters
Arrays are the most efficient collection for random access and are the foundation for numerical computing, image processing, and performance-critical algorithms. Durga Antivirus Pro uses arrays for signature databases.
Real-World Use
Arrays are used in scientific computing, Machine Learning data buffers, image processing pixels, and any scenario requiring fast indexed access.
flowchart LR
A["Arrays"] --> B["Creation"]
B --> C["Indexing"]
C --> D["Transformations"]
D --> E["Performance"]
A:::current --> B
style A fill:#2563eb,stroke:#2563eb,color:#fff
style B fill:#dbeafe,stroke:#2563eb,color:#1e40af
style C fill:#dbeafe,stroke:#2563eb,color:#1e40af
style D fill:#dbeafe,stroke:#2563eb,color:#1e40af
style E fill:#f1f5f9,stroke:#94a3b8,color:#64748b
Creating Arrays
// Literal syntax
let empty = [||]
let numbers = [|1; 2; 3; 4; 5|]
let strings = [|"apple"; "banana"; "cherry"|]
// Range syntax
let range = [|1..10|]
let stepped = [|0..2..20|]
// Initialization
let zeros = Array.zeroCreate 5 // [|0; 0; 0; 0; 0|]
let squares = Array.init 5 (fun i -> i * i) // [|0; 1; 4; 9; 16|]
// Create from list
let fromList = List.toArray [1; 2; 3]
Indexed Access
let arr = [|10; 20; 30; 40; 50|]
// Read
let first = arr.[0] // 10
let third = arr.[2] // 30
// Write (mutate)
arr.[1] <- 25
// arr is now [|10; 25; 30; 40; 50|]
// Slice
let slice = arr.[1..3] // [|25; 30; 40|]
let from2 = arr.[2..] // [|30; 40; 50|]
let upTo3 = arr.[..3] // [|10; 25; 30; 40|]
Array Transformations
let numbers = [|1; 2; 3; 4; 5|]
let doubled = numbers |> Array.map (fun x -> x * 2)
// [|2; 4; 6; 8; 10|]
let evens = numbers |> Array.filter (fun x -> x % 2 = 0)
// [|2; 4|]
let sum = numbers |> Array.sum // 15
let product = numbers |> Array.reduce (*) // 120
Creating New Arrays
let arr = [|3; 1; 4; 1; 5|]
// Append creates new array
let larger = Array.append arr [|9; 2|]
// [|3; 1; 4; 1; 5; 9; 2|]
let sorted = Array.sort arr // New sorted array
let reversed = Array.rev arr
// Concat multiple arrays
let combined = Array.concat [|arr; [|10|]; [|20|]|]
Array vs List
// Arrays: mutable, O(1) index, O(n) prepend
// Lists: immutable, O(n) index, O(1) prepend
// Array operations return new arrays
// (F# Arrays are functionally immutable by convention)
let arr = [|1; 2; 3|]
let newArr = Array.map (fun x -> x + 1) arr
// arr is unchanged
Multi-Dimensional Arrays
// 2D array
let matrix = array2D [[1; 2; 3]; [4; 5; 6]]
matrix.[0, 1] // 2
// Create 2D
let zeros2D = Array2D.zeroCreate 3 3
// Jagged array
let jagged = [|[|1; 2|]; [|3; 4; 5|]|]
jagged.[0].[1] // 2
Performance
// Arrays are the fastest F# collection
// Use arrays for:
// - Random access patterns
// - Numerical computations
// - Buffer processing
// - Interop with .NET libraries
// Mutable optimization
let processInPlace (arr: int[]) =
for i in 0..arr.Length-1 do
arr.[i] <- arr.[i] * 2
Common Mistakes
1. IndexOutOfBounds
Accessing arr.[length] (beyond last element) throws an exception. Check bounds with arr.Length.
2. Confusing array and list syntax
Arrays use [| |], lists use [ ]. They look similar but behave very differently.
3. Assuming functional purity
Array.map creates a new array. But operations that modify individual elements (arr.[i] <- v) mutate in place.
4. Large array copies
Array.append and other functions create full copies. For large arrays, consider mutation or different data structures.
5. Forgetting .NET array compatibility
F# arrays are .NET System.Array. They can be passed to C# methods and vice versa.
Practice Questions
1. How do you access an element at index 3?
Use arr.[3]. Arrays are zero-indexed.
| **2. What is the difference between [ | 1; 2 | ] and [1; 2]?** |
|---|
3. How do you create a slice of an array?
Use range syntax: arr.[start..end] creates a new array from the specified range.
Challenge: Write a function that reverses an array in-place without creating a new array.
FAQ
{{< faq question="Are F# arrays mutable?" >}}
Yes, F# arrays are mutable by default. You can modify elements using arr.[index] <- value.
{{< /faq >}}
{{< faq question="When should I use arrays over lists?" >}} Use arrays for fast indexed access, mutable operations, numerical computing, and compatibility with .NET libraries. {{< /faq >}}
{{< faq question="Can arrays be resized?" >}}
No, arrays are fixed-size. Use ResizeArray<T> (C# List) for dynamically sized mutable collections.
{{< /faq >}}
{{< faq question="How do I convert an array to a list?" >}}
Use Array.toList arr or List.ofArray arr.
{{< /faq >}}
{{< faq question="Are array operations like map functional?" >}}
Array.map returns a new array without modifying the original. But the new array itself is mutable.
{{< /faq >}}
Mini Project
Implement a simple image filter using array operations:
type Image = int[,]
let grayscale (img: Image) =
Array2D.init (Array2D.length1 img) (Array2D.length2 img)
(fun i j -> img.[i, j] / 3)
let invert (img: Image) =
Array2D.init (Array2D.length1 img) (Array2D.length2 img)
(fun i j -> 255 - img.[i, j])
let brighten factor (img: Image) =
Array2D.init (Array2D.length1 img) (Array2D.length2 img)
(fun i j -> min 255 (img.[i, j] * factor))
What's Next
Now that you understand arrays, explore sequences for lazy, potentially infinite data.
| Topic | Description | Link |
|---|---|---|
| F# Sequences | Lazy sequences | {{< ref "09-sequences" >}} |
| F# Records | Record types | {{< ref "10-records" >}} |
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro