Explore arrays in F#. This tutorial demonstrates how to use fixed-size collections in F# programming.
last modified May 1, 2025
In this article, we show how to work with arrays in F#.
An array is a fixed-size, zero-based, mutable collection of consecutive elements. The elements are of the same data type.
let vals = [| 1; 2; 3; 4; 5 |]
An array can be created using an array literal. An array literal consists of elements separated with semicolons between [| and |].
let vals = [| 1 2 3 4 5 |]
In an alternative syntax, the semicolons are optional.
The following is a simple array example.
main.fsx
let vals = [| 1; 2; 3; 4; 5; 6 |]
printfn “%A” vals printfn “%d” vals.Length
We have an array of integers. We print the contents of the array and then the size of the array.
let vals = [| 1; 2; 3; 4; 5; 6 |]
We define a new array of integers with an array literal.
printfn “%A” vals
With the %A format specifier, we pretty-print the array.
printfn “%d” vals.Length
We get the size of an array with Length.
λ dotnet fsi main.fsx [|1; 2; 3; 4; 5; 6|] 6
In the next example, we get the head and tail of an array.
main.fsx
let vals = [| 1; 2; 3; 4; 5; 6 |]
printfn “%d” (Array.head vals) printfn “%A” (Array.tail vals)
We print the head and tail of the array of integers.
printfn “%d” (Array.head vals)
The Array.head prints the first element of the array.
printfn “%A” (Array.tail vals)
With Array.tail function, we get all but first elements (the tail) of the given array.
λ dotnet fsi main.fsx [|2; 3; 4; 5; 6|] 1 [|2; 3; 4; 5; 6|]
In the next example, we loop over the elements of an array.
main.fsx
let vals = [| 1; 2; 3; 4; 5; 6 |]
vals |> Array.iter (printfn “%d”)
printfn “————————”
for e in vals do printfn “%d” e
There are two basic ways of array iteration.
vals |> Array.iter (printfn “%d”)
The Array.iter is the functional way of looping over array elements.
for e in vals do printfn “%d” e
The classic, imperative way is via a for loop.
1 2 3 4 5 6
Array elements are accessed through their indexes.
main.fsx
let words = [| “pen”; “cup”; “dog”; “person”; “cement”; “coal”; “spectacles”; “cup”; “bread” |]
let w1 = Array.item 1 words printfn “%s” w1
let w2 = words[0] printfn “%s” w2
let i1 = Array.findIndex(fun e -> e = “cup”) words printfn $“The first index of cup is {i1}”
let i2 = Array.findIndexBack(fun e -> e = “cup”) words printfn $“The last index of cup is {i2}”
The program contains array indexing operations.
let w1 = Array.item 1 words
We get the second item of the array with Array.item.
let w2 = words[0]
We can also use the classic C style syntax.
let i1 = Array.findIndex(fun e -> e = “cup”) words
Fith Array.findIndex, we find the first element that satisfies the given predicate function.
let i2 = Array.findIndexBack(fun e -> e = “cup”) words
Fith Array.findIndexBack, we find the last element that satisfies the given predicate function.
λ dotnet fsi main.fsx cup pen The first index of cup is 1 The last index of cup is 7
We can modify array elements with <- or Array.set.
main.fsx
let words = [| “pen”; “cup”; “dog”; “person”; “cement”; “coal”; “spectacles”; “cup”; “bread” |]
printfn “%A” words
words[0] <- “pencil” Array.set words 6 “specs”
printfn “%A” words
We have an array of strings. We modify the first and the sixth element.
λ dotnet fsi main.fsx [|“pen”; “cup”; … “coal”; “spectacles”; “cup”; “bread”|] [|“pencil”; “cup”; … “coal”; “specs”; “cup”; “bread”|]
Two-dimensional arrays can be created with array2D operator.
main.fsx
let vals = array2D [ [ 1; 2; 3]; [4; 5; 6]; [7; 8; 9] ]
printfn “%A” vals printfn “%d” vals[0, 0] printfn “%A” vals[0, 0..2] printfn “%A” vals[0..2, 0]
We create a two-dimensional array of integers.
printfn “%d” vals[0, 0]
We get the first element of the first row.
printfn “%d” vals[1, 2]
We get the third element of the second row.
printfn “%A” vals[0, 0..2]
We get the first row.
printfn “%A” vals[0..2, 0]
We get the first column.
λ dotnet fsi main.fsx [[1; 2; 3] [4; 5; 6] [7; 8; 9]] 1 6 [|1; 2; 3|] [|1; 4; 7|]
The Array.map function applies the given function to each of the elements of the collection.
main.fsx
let vals = [| 1..10 |]
let res = Array.map(fun e -> e * 2) vals printfn “%A” res
We apply a map function on an array of integers.
let vals = [| 1..10 |]
We define an array with a range operator.
let res = Array.map(fun e -> e * 2) vals
Each of the elements of the array is multiplied by 2. The result is assigned to the res variable.
λ dotnet fsi main.fsx [|2; 4; 6; 8; 10; 12; 14; 16; 18; 20|]
We can filter array elements with Array.filter.
main.fsx
let vals = [| -3; -2; 0; 1; -5; 7; 9 |] let words = [| “sky”; “war”; “rock”; “ocean”; “cloud”; “water” |]
let pos = Array.filter(fun e -> e > 0) vals printfn “%A” pos
let res = Array.filter(fun (e:string) -> e.StartsWith(“w”)) words printfn “%A” res
In the program, we find out all positive numbers from an array of integers and all strings which start with ‘w’ in an array of words.
let pos = Array.filter(fun e -> e > 0) vals
The Array.filter function takes a predicate function. All elements must satisfy the given predicate.
let res = Array.filter(fun (e:string) -> e.StartsWith(“w”)) words
Sometimes, it is necessary to help the compiler with an explicitly type definition.
λ dotnet fsi main.fsx [1; 7; 9] [“war”; “water”]
Arrays can be merged with Array.concat or with an array comprehension. Array.unique returns an array that contains no duplicate entries.
main.fsx
let a = [| 1; 2; 3; 4 |] let b = [| 4; 4; 5; 6 |]
let d = Array.concat [a; b] let c = Array.distinct d
let e = [| yield! a; yield! b |] let f = Array.distinct e
printfn “%A” c printfn “%A” d printfn “%A” e printfn “%A” f
The program merges two arrays.
let d = Array.concat [a; b]
We merge two arrays with Array.concat.
let c = Array.distinct d
The duplicates are removed with Array.distinct.
let e = [| yield! a; yield! b |]
The yield! inserts all the items of another sequence into this sequence being built.
λ dotnet fsi main.fsx [|1; 2; 3; 4; 5; 6|] [|1; 2; 3; 4; 4; 4; 5; 6|] [|1; 2; 3; 4; 4; 4; 5; 6|] [|1; 2; 3; 4; 5; 6|]
In the next example, we sort integers.
main.fsx
let nums = [| -1; 6; -2; 3; 0; -4; 5; 1; 2 |]
nums |> Array.sort |> printfn “%A” nums |> Array.sortDescending |> printfn “%A”
nums |> Array.sortBy (abs) |> printfn “%A” nums |> Array.sortByDescending (abs) |> printfn “%A”
We have an array of integers. We sort them with Array.sort and Array.sortDescending.
nums |> Array.sortBy (abs) |> printfn “%A” nums |> Array.sortByDescending (abs) |> printfn “%A”
With the help of the abs, we sort integers regarless of their sign.
λ dotnet fsi main.fsx [|-4; -2; -1; 0; 1; 2; 3; 5; 6|] [|6; 5; 3; 2; 1; 0; -1; -2; -4|] [|0; -1; 1; -2; 2; 3; -4; 5; 6|] [|6; 5; -4; 3; -2; 2; -1; 1; 0|]
In the next example, we sort an array of records.
main.fsx
type User = { Name: string Occupation: string Salary: int }
let users = [| { Name = “John Doe” Occupation = “gardener” Salary = 1280 } { Name = “Roger Roe” Occupation = “driver” Salary = 860 } { Name = “Tom Brown” Occupation = “shopkeeper” Salary = 990 } |]
users |> Array.sortBy (fun u -> u.Salary) |> Array.iter (fun u -> printfn “%A” u)
printfn “——————————–”
users |> Array.sortByDescending (fun u -> u.Occupation) |> Array.iter (fun u -> printfn “%A” u)
The program contains an array of User records. We sort the users by their salaries and occupation.
users |> Array.sortBy (fun u -> u.Salary) |> Array.iter (fun u -> printfn “%A” u)
The users are sorted by salaries in ascending order with Array.sortBy.
users |> Array.sortByDescending (fun u -> u.Occupation) |> Array.iter (fun u -> printfn “%A” u)
Here, the users are sorted by their occupation in descending order with sortByDescending.
{ Name = “Tom Brown” Occupation = “shopkeeper” Salary = 990 } { Name = “John Doe” Occupation = “gardener” Salary = 1280 } { Name = “Roger Roe” Occupation = “driver” Salary = 860 }
Array comprehension is a powerful syntax to generate arrays. Array comprehensions provide a concise way to create arrays.
In F#, we can create array comprehensions with ranges and generators.
main.fsx
let vals = [| -1; 0; 2; -2; 1; 3; 4; -6 |]
let pos = [| for e in vals do if e > 0 then yield e |]
printfn “%A” pos
printfn “———————————”
[| for e in 1 .. 100 -> e * e |] |> printfn “%A”
printfn “———————————”
[| for a in 1 .. 100 do if a % 3 = 0 && a % 5 = 0 then yield a|] |> printfn “%A”
printfn “———————————”
let vals3 = [| for x in 1 .. 3 do for y in 1 .. 10 -> x, y |]
printfn “%A” vals3
In F#, array comprehensions use for loops, if conditions and the yield keyword.
let vals = [| -1; 0; 2; -2; 1; 3; 4; -6 |]
let pos = [| for e in vals do if e > 0 then yield e |]
We have aan array of values. A new array is constructed with an array comprehension. It contains only positive values.
[| for e in 1 .. 100 -> e * e |] |> printfn “%A”
We can use ranges in array comprehensions.
[| for a in 1 .. 100 do if a % 3 = 0 && a % 5 = 0 then yield a|] |> printfn “%A”
Here we use two if conditions.
let vals3 = [| for x in 1 .. 3 do for y in 1 .. 10 -> x, y |]
Also, it is possible to use two for loops.
[(1, 1); (1, 2); (1, 3); (1, 4); (1, 5); (1, 6); (1, 7); (1, 8); (1, 9); (1, 10); (2, 1); (2, 2); (2, 3); (2, 4); (2, 5); (2, 6); (2, 7); (2, 8); (2, 9); (2, 10); (3, 1); (3, 2); (3, 3); (3, 4); (3, 5); (3, 6); (3, 7); (3, 8); (3, 9); (3, 10)]
In this article we have worked with arrays in F#.
My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.