Introduction
Arrays in F# are mutable data types. I started intentionally with this line, as FSharp(F#) is a functional programming language, and the paradigm of the language promotes immutability. So, whenever there is a mutable type or value, be careful with the usage. Let's go back to the main topic, i.e., Arrays. In this post, we'll see how to initialize, iterate, update, and manipulate arrays in FSharp(F#). In this post, we'll cover only one-dimensional array. Maybe we can discuss 2D, 3D, and Jagged arrays in an advanced array post in the future.
Static array initialization
In FSharp(F#), we initialize the array with the following notations.
let fruits = [|"Apple"; "Orange"; "Grapes"|]
// or using every item in a separate line without a separator
let fruits = [| "Apple" "Orange" "Grapes" |]
Note. The additional symbol | (pipe) used with square braces to declare the array. Also, the separator is no longer a ",", comma, but it's a ";" semicolon. Here's an example of an array of integers and a possible mistake that can be made by a C# developer without getting any compile-time error.
let arr = [| 1; 2; 3; 4 |]
Possible mistakes #1
let arr1 = [| 1, 2, 3 |]
// This is an array of tuples with one element, so no error is displayed.
// The ',' separator is used to create tuples.
Possible mistakes #2
let arr2 = [1; 2; 3]
// This is also valid, but this would be a list, and it's "IMMUTABLE".
Initialization using sequence expressions
// Array of squares of positive integers from 1 to 10
let arr3 = [| for i in 1 .. 10 -> i * i |]
Output
Initialization using Array module
Array.empty
// Create an empty array without specifying the type.
let array1 = Array.empty
// Create an empty array with a type annotation.
let array2 : int array = Array.empty
// Create an empty array with type inference.
let array3 = Array.empty
// Print the length of the empty array.
printfn "Length of empty array: %d" array3.Length
Output.
Array.create
Creates an array of a specified size and sets all the elements to provided values.
// Create an array of length 10, with all elements initialized to the default value -1.
let arrayOfTenZeroes : int array = Array.create 10 (-1)
// Create a bool array with a length of 10, with all elements initialized to the default value true.
let primeFlaggedArr : bool array = Array.create 10 true
Note. In the end of this article, we'll solve the find prime number problem using Sieve of Eratosthenes.
Array.zeroCreate
Creates an array, given a dimension and a function to generate the elements.
// create a bool array with default values (false)
let primeFlaggedArr : bool array = Array.zeroCreate 10
Array.init
Creates an array, given a dimension and a function to generate the elements.
// Another way to create an array of squares starting from 1 to 10
printfn "Array of squares: %A" (Array.init 10 (fun index -> index * index))
Accessing array elements
You can access array elements by using a dot operator (.) and brackets ([ and ]).
let fruits = [| "Apple" "Orange" "Grapes" |]
let firstFruit = fruits.[0]
Accessing a range of values from an array using sliced notation.
// Accesses elements from 0 to 2.
arr.[0..2]
// Accesses elements from the beginning of the array to 2.
arr.[..2]
// Accesses elements from 2 to the end of the array.
arr.[2..]
Few more honorable mentions or generally used functions are Array.get, Array.set.
Replacing existing value using index
Arrays are mutable so you can replace any existing value by accessing it via index and assigning a new value with the '<-' operator.
// Updating the value of an item in an array using an index
let fruits1 = [|
"Apple"
"Orange"
"Grapes"
|]
fruits1.[0] <- "Mango"
let print () =
for fruit in fruits1 do
printfn "%s" fruit
print ()
Output
Iterating through array elements
Let's create a function that takes an array of string and converts the values to upper case.
let MakeUpper(arr : string array) =
for i in 0 .. arr.Length - 1 do
Array.set arr i (arr.[i].ToUpper())
printfn "%s" arr.[i]
In Visual Studio, select the function and run it in F# interactive.
Output
With a variant of the for loop (foreach alike).
let PrintUpper(arr : string array) =
for (fruit) in arr do
printfn "%s" (fruit.ToUpper())
Output
So now we are pretty much good to start with playing around array. Let's try to solve a few problems using arrays to get up to speed. As I discussed before, we'll be solving the finding prime number problem using Sieve of Eratosthenes. Here's a function that is based on the theory given at the source.
// Print prime numbers in a series up to n
let PrimeSieve(n : int) =
let sequence = [|1..n|]
let isPrime = Array.create n true
let maxSquareRoot : int = System.Convert.ToInt32(System.Math.Sqrt(float n))
let candidate = 2
for i in candidate..maxSquareRoot do
if isPrime.[i] then
let mutable j = i * i
while j < n do
isPrime.[j] <- false
j <- j + i
done
for index in 0..n - 1 do
if isPrime.[index] then
printf "%d, " index
// Call the PrimeSieve function with your desired 'n' value
PrimeSieve 100
Output
Here's the equivalent code in C#.
public static void PrimeSieve(int n)
{
bool[] isPrime = new bool[n + 1];
int maxSquareRoot = (int)Math.Sqrt(n);
int candidate = 2;
// Additional loop to initialize the bool array with default value
for (int ind = 0; ind < isPrime.Length; ind++)
{
isPrime[ind] = true;
}
for (int i = candidate; i < Math.Sqrt(n); i += 1)
{
if (isPrime[i])
{
for (int j = i * i; j < n; j = j + i)
{
isPrime[j] = false;
}
}
for (int k = 0; k < n; k++)
{
if (isPrime[k])
{
Console.WriteLine(k);
}
}
}
}
Although the given solution in F# is not the best and not recommended because we're using much of mutable types like any other imperative language. In upcoming posts, we'll solve the same problem with immutable types and without using mutable.
Here's a few exercises for you.
// Guess the output, Write your answer in the comments.
let guessOutput =
for i in [|9..7..30|] do
printfn "%d" i
Read more articles on FSharp(F#).