Introduction
F# is an excellent programming language that blends the functional and object-oriented paradigms.
Arrays are a fundamental data structure in F#.
This blog post is a deep-dive introduction to F# arrays, learning about their features, benefits, and informative, practical code examples.
Understanding F# Arrays
- An array in F# is a collection of elements of the same type that are organized identically.
- Arrays are well-known for their constant-time indexing, making them ideal for scenarios requiring efficient random access.
Array Creation
F# arrays can be created in multiple ways.
Let's explore some of these methods.
Array Literal
let fruits = [|"apple"; "avocado";"dragon fruit"|]
In creating an array, we need to put elements of the same type in a consecutive way, surrounded by the [| |] symbols and separated by semicolons.
Please remember this: it is essential because other languages often use commas for that, and in F#, commas are only for tuples.
Another way to define an array with F# is via line breaks instead of semicolons.
Let's try to take a look.
let cars = [| "Honda"
"BMW"
"Toyota" |]
For the whole code sample, please see the code below.
let fruits =
[|"apple"; "avocado";"dragon fruit"|]
printfn "Array contents %A" fruits
let cars = [|
"Honda"
"BMW"
"Toyota"
|]
printfn "My favorite car collections: %A" cars
Note. In F#, you can log the contents of arrays using the printfn function or other logging mechanisms.
Array Functions
Array.init Function
let evenNumbers = Array.init 5 (fun (index: int) -> index * 2)
(* Result: evenNumbers collections: [|0; 2; 4; 6; 8|] *)
printfn "evenNumbers collections: %A" evenNumbers
The Array.init is a function used to create and initialize arrays.
Let's try to dissect more.
- 5 - is the length argument, indicating that you must create an array with five elements.
- fun (index:int) -> index * 2 - is a lambda or anonymous function that specifies how to initialize each array element. In this case, it takes an index of type int and multiplies it by 2. This Function is applied to each array index to calculate the corresponding value.
Array.zeroCreate Function
let tenZero:int[] = Array.zeroCreate 10
(* Result: Ten zeros collections: [|0; 0; 0; 0; 0; 0; 0; 0; 0; 0|]*)
printfn "Ten zeros collections: %A" tenZero
The Array.zeroCreate - is a function used to create an array of a specified length and initialize all its elements with a default value. In our example,10 - the length of the array needs to be created.
Array.create Function
let tripleA = Array.create 3 "A" printfn "Triple A %A" tripleA
The Array.create - is a function to create an array with a length (specified 3) and initialize all elements by passing a value (specified A).
This is a common way to initialize an array with a specific length and default values in F#.
Array Manipulation
Updating Array Elements
let mutable names = [|"Jin"; "John"; "Paul"|]
names.[0] <- "James"
(* Result: The names collection [|"James"; "John"; "Paul"|]*)
printfn "The names collection %A" names
- let mutable names = [|"Jin"; "John"; "Paul"|]: This line declares a mutable array of named names and initializes it with three elements: "Jin"; "John"; "Paul". The mutable keyword allows you to modify the array's contents after creation.
- names.[0] <- "James": This line modifies the first element of the names array. It changes "Jin" to "James". In F#, array elements are zero-indexed, so [0] it refers to the first element.
- printfn "The names collection %A" names: This line prints the contents of the names array to the console using printfn. The %A format specifier prints arrays in a readable format.
Concatenating Arrays
let blueStrikeForce = [|"cyclops"; "beast"; "gambit"; "jubilee"|]
let goldStrikeForce = [|"storm";"colosus";"bishop"|]
let xmen = Array.append blueStrikeForce goldStrikeForce
(* Result: The xmen mutants [|"cyclops"; "beast"; "gambit"; "jubilee"; "storm"; "colosus"; "bishop"|]*)
printfn "The xmen mutants %A" xmen
- blueStrikeForce is an array containing the names of some X-Men characters.
- goldStrikeForce is another array containing the names of additional X-Men characters.
- Array. append is used to concatenate the two arrays, resulting in a new array named xmen. This array contains all the X-Men characters from both blueStrikeForce and goldStrikeForce.
- printfn is used to print the concatenated xmen array, which will output the names of all X-Men mutants.
Subarrays
let members = [|"Paul";"Paulene";"Jack";"John"|]
let newMembers = Array.sub members 2 2
(* Result: The newMembers [|"Jack"; "John"|]*)
printfn "The newMembers %A" newMembers
- Members is an array containing names of individuals.
- Array.sub is used to create a subarray from the members array. It takes two arguments: the starting index (2 in this case) and the length of the subarray (2 in this case). So, it starts at index 2 (which is "Jack") and includes the following 2 elements, resulting in a subarray containing "Jack" and "John".
- printfn is used to print the newMembers array, which will output the names of the new members.
Flattening Arrays
let nestedArrays = [|[|"adobo";"sinigang";"pancit"|];[|"ramen";"california maki"|]|]
let flattenedArrays = Array.collect (fun (arr) -> arr) nestedArrays
(* Result: he flattenedArrays [|"adobo"; "sinigang"; "pancit"; "ramen"; "california maki"|]*)
printfn "The flattenedArrays %A" flattenedArrays
- nestedArrays is an array containing two subarrays containing strings representing different dishes.
- Array.collect is used to flatten the nested arrays. It takes a function that maps each element nestedArrays to a new array. In this case, the Function returns each subarray as is, effectively flattening the structure.
- printfn prints the flattenedArrays, which will output all the dish names in a single flattened array.
Reversing Arrays
let numbersFrom10to1 = [|10;9;8;7;6;5;4;3;2;1;0|]
let numbersInOrder = Array.rev numbersFrom10to1
(* Result: The numbersInOrder [|10; 9; 8; 7; 6; 5; 4; 3; 2; 1; 0|]*)
printfn "The numbersInOrder %A" numbersFrom10to1
- numbersFrom10to1 is an array containing integers from 10 down to 0 in descending order.
- Array.rev is used to reverse the order of the elements, creating a new array named numbersInOrder.
- printfn print the numbersFrom10to1 array, which will output the original array, not the reversed one.
Iterating Through Arrays
There are convenient ways to iterate through arrays using various looping constructs:
The for Loop
let vowels = [|"a"; "e"; "i"; "o"; "u"|]
for vowel in vowels do
printf "%s, " vowel
Output: a, e, i, o, u,
The Array.iter Function
Array.iter (fun vowel -> printfn "%s" vowel) vowels
Output
a
e
i
o
u
For more info about iterations (loop concepts), I've created/posted an article on C# Corner. You can check it here: https://www.c-sharpcorner.com/article/f-sharp-for-and-while-loop-concepts/.
Array Tips
While F# arrays offer various benefits, developers should be aware of potential pitfalls.
- Immutability: F# arrays are immutable by default. However, if you need to modify an array frequently, consider using mutable arrays.
- Resizing Overhead: As a developer, we need to be aware that resizing an array requires the creation of a new collection and copying elements. If frequent resizing is expected, different data structures may be preferable.
- Functional Style: F# promotes functional programming techniques. Moreover, mutable arrays are available, so we can explore functional alternatives such as lists and sequences that may better accord with F#'s paradigm.
Summary
In this blog post, we've covered array creation, element access, manipulation, iteration, and usage tips, including additional array functions like Array.sub, Array.collect, Array.concat, Array.rev, and Array.append.
With this knowledge, you can decide when and how to use F# arrays in your projects. I hope you have enjoyed this article, as I enjoyed it while writing. Till next time, happy cloud computing and programming!