Click here to Skip to main content
15,885,546 members
Articles / Programming Languages / F#

F#12: Arrays

Rate me:
Please Sign up or sign in to vote.
4.67/5 (2 votes)
28 Mar 2014CPOL6 min read 20.5K   4  
F#12: Arrays

No language would be complete without arrays (at least in my opinion). They are an excellent structure. F# is of course no fool, and includes them (as you would expect), so this blog will concentrate on looking at using arrays in F#.

Creating Arrays

There are several ways to create arrays, just as there were with List and Sequences. You have the following choices:

  • Inline initialisation (where you provide the values)
  • Using comprehensions (that we say with List and Sequences)
  • Using the Array module itself which has several array creation functions

Here are some examples:

F#
/// The empty array
let emptyArray = [| |]

// inline array values
let fruitArray = [| "bananna"; "apple"; "pear"; "mango"; "rambutan"; "lychee" |]

// use list comprehension syntax
let numberArray = [| 1 .. 10 |]

/// An array containing only the words "hello" and "world"
let onlyLArray = [| for word in fruitArray do
                    if word.StartsWith("l") then 
                        yield word |]

// An array initialized by index and containing the the number squared
// using the Array module directly
let generatorArray = Array.init 11 (fun n -> n * 2)

Which when run looks like this:

image

BEWARE

Now you need to be slightly careful with your syntax (a lot of F# is like this), there is really not much difference between how you declare lists and arrays. See the screen shot below. The key difference is the use of the “[|” and “|]”which arrays use and lists do not. One to watch for. We will also see some more quite similar syntax to this further down the line, but that is when we look at passive/active patterns, but we ain't there yet, so let's not cloud the waters with even more syntax for now.

image

Arrays Of Arrays

We can also make arrays of arrays, which can be done as follows:

F#
/// The empty array of arrays
let emptyArrayOfArrays = [|  [| |] ; [| |]  |]
 
// array of arrays
let arrayOfArrays = [|   [| 1;2;3|] ; [| 4;5;6|] |]

Which when run looks like this:

image

Multi Dimensional Arrays

As you would expect, we can also create different dimensioned arrays. There is however no inline syntax (array literal as it is known in F#) for working with 2D arrays (or higher, yes F# supports them up to 4D, if you are mad enough to need it, F# supports it).

We can however use one of the built in F# operators. Here are some examples that show you how to create 2D and 3D arrays:

F#
// use the array2D operator
let array2D = array2D [ [ 1;2]; [2;3]]

// 3d array
let array3DInit = Array3D.init 3 3 3 (fun a b c -> a * 2)

Which when run looks like this:

image

Everything looks cool with the 2D array, but what is the weird “[|rank=3|]” gibberish. That is actually just do with the printfn function and a bit of a red herring if we try and execute the 3D array line in the FSI window, we see the truth.

image

Which is as expected a 3D array, which is expressed as “int [,,]”, a 2D int array would have just been “int [,]”. The rank simply tells us the dimension count.

As can be seen here with a 4D array (heaven forbid, you need one):

image

NOTE

It should be noted that the following modules have way less available functions than the rather more common Array F# module:

  • Array2D
  • Array3D
  • Array4D

Indexing Into Arrays

So now that we have seen how to create arrays, we should see how we can get values out of array elements. It is just worth noting that arrays in F# ARE 0 index based.

Here are some examples, showing how to index into single dimension arrays, and arrays of arrays, and a 2D array.

F#
// single array
let singleArray = [|  1;2;3;4;5;6 |]

// array of arrays
let arrayOfArrays = [|   [| 1;2;3|] ; [| 4;5;6|] |]

// use the array2D operator
let array2D = array2D [ [ 1;2;3;4;5]; [11;12;13;14;15]]

printfn "singleArray element [0] = %A" singleArray.[2]
printfn "\r\n"
printfn "arrayOfArrays element [1] [2] = %A" arrayOfArrays.[1].[2]
printfn "\r\n"
printfn "array2D element [1,1] = %A" array2D.[1,1]

Which when run looks like this:

image

See how we need to index into arrays using the “.[0]” (where 0 is the index” syntax. This also applies for arrays of arrays. However for multidimensional arrays, we use the “[1,1]” syntax.

Mutating Array Element State

So now that you have seen how to index into arrays, you are probably wondering how you can change the state of an array element. In F#, this is done with the assignment operator “<-“.

Here are some examples, showing how to assign new values into single dimension arrays, and arrays of arrays, and a 2D array.

F#
// single array
let singleArray = [|  1;2;3;4;5;6 |]

// array of arrays
let arrayOfArrays = [|   [| 1;2;3|] ; [| 4;5;6|] |]

// use the array2D operator
let array2D = array2D [ [ 1;2;3;4;5]; [11;12;13;14;15]]

printfn "BEFORE ASSINMENT : singleArray element [0] = %A" singleArray.[2]
printfn "Assigning 999"
// ************ Assign new value *********************
singleArray.[2] <- 999
printfn "AFTER ASSINMENT : singleArray element [0] = %A" singleArray.[2]
printfn "\r\n"

printfn "BEFORE ASSINMENT : arrayOfArrays element [1] [2] = %A" arrayOfArrays.[1].[2]
printfn "Assigning 423"
// ************ Assign new value *********************
arrayOfArrays.[1].[2] <- 423
printfn "AFTER ASSINMENT : arrayOfArrays element [1] [2] = %A" arrayOfArrays.[1].[2]
printfn "\r\n"
        
printfn "BEFORE ASSINMENT : array2D element [1,1] = %A" array2D.[1,1]
printfn "Assigning 8989"
// ************ Assign new value *********************
array2D.[1,1] <- 8989
printfn "AFTER ASSINMENT : array2D element [1,1] = %A" array2D.[1,1]

Which when run will give the following results:

image

Slicing Arrays

Sometimes, you may also want to slice arrays to only grab a certain section of the original array. F# has built in support for this, it is called an array slice.

You may choose to slice an original array like this:

  • Specify both lower and upper bound, which will copy only those elements between your lower/upper bounds
  • Specify lower bound, which will copy only those elements above your lower bound
  • Specify upper bound, which will copy only those elements below your upper bond
  • Specify wild card, which will in effect copy the entire array

Here is how it is done, in practice:

F#
let arrayof10 = [|1..10|]

// Specify lower and upper bound for slice
let arraySlice0To2 = arrayof10.[0..2]

// Specify lower bound only for slice
let arraySlice4ToEnd = arrayof10.[4..]

// Specify upper bound only for slice
let arraySliceUntil6 = arrayof10.[..6]

// Specify wild card, which clones array
let arrayClone = arrayof10.[*]        

printfn "arrayof10 = %A" arrayof10
printfn "\r\n"
printfn "arraySlice0To2 = %A" arraySlice0To2
printfn "\r\n"
printfn "arraySlice4ToEnd = %A" arraySlice4ToEnd
printfn "\r\n"
printfn "arraySliceUntil6 = %A" arraySliceUntil6
printfn "\r\n"
printfn "arrayClone = %A" arrayClone

Which when run, gives the following results:

image

The Array Module

As with List and Sequence, Arrays are a very important type in F#, as such it should be no surprise that they too have good MSDN documentation. As such, just as I have stated with List and Sequences, it would be fruitless me just regurgitating what is already available on MSDN. There is no point to that.

The F# Array module MSDN documentation can be found here.

I think it is always nice to see a few examples, though, so in fitting with what I have been so far in this series, I will show a few demos, but you should refer to MSDN for the full list of the Array module functions.

I have picked a few random functions which I think are cool, and useful, that said the F# Array module holds many fascinating and useful functions.

Find

Returns the first element for which the given function returns true. Raise KeyNotFoundException if no such element exists.

FindIndex

Returns the index of the first element in an array that satisfies the supplied condition. Raises KeyNotFoundException if none of the elements satisfy the condition.

Here is a small demo that covers both Find, and FindIndex, where we try and Find the element value when the element contains 2, and also its index.

F#
let arrayof10 = [|1..10|]
let element = Array.find (fun elem -> elem = 3) arrayof10
let index = Array.findIndex (fun elem -> elem = 3) arrayof10
printfn "The first element that is 3 is %d and its index is %d." element index

Which when run looks like this:

image

ForAll

Tests whether all elements of an array satisfy the supplied condition.

Here is a small sample that wants all the array elements to be > 0.

F#
//simple way of writing it 
let allAbove0 = (Array.forall (fun elem -> elem > 0) [| 0; 1; 2; 3 |])
printfn "(Array.forall (fun elem -> elem > 0) [| 0; 1; 2; 3 |]) = %A" allAbove0

let allAbove0 = (Array.forall (fun elem -> elem > 0) [| 1; 2; 3 |])
printfn "(Array.forall (fun elem -> elem > 0) [| 1; 2; 3 |]) %A" allAbove0

Which when run produces the following results:

image

We could also rewrite this use partial application (which is a F# topic I have not covered just yet), but essentially it allows us to partially apply the parameters to a function, then bind that function, and then at some later point in time, supply the remaining parameters. Which in the example below, would be the final parameter (the array itself).

F#
//use partial application
let allPositive = Array.forall (fun elem -> elem > 0)
let allAbove0 = (allPositive [| 0; 1; 2; 3 |])
printfn "(allPositive [| 0; 1; 2; 3 |]) = %A" allAbove0

let allPositive = Array.forall (fun elem -> elem > 0)
let allAbove0 = (allPositive [| 1; 2; 3 |])
printfn "(allPositive [| 1; 2; 3 |]) = %A" allAbove0

Init

Creates an array given the dimension and a generator function to compute the elements.

As you can imagine this is especially useful when you want to initial an array with your own choice of seed data. Here is an example where we fill the entire array with the integer value 5 (God knows why you would want a whole array of 5s but meh).

F#
printfn "(Array.init 10 (fun index -> 5))" 
let array = (Array.init 10 (fun index -> 5))
printfn "%A" array

Which when run, produces the following results:

image

Partition

Splits the collection into two collections, containing the elements for which the given predicate returns true and false respectively.

Here is a small example where we want the results partitioned based on whether the array elements are > 3 or not. So we would expect to get a tuple returned with 2 arrays in it, where one array held elements whose values are < 3, and second tuple value should be an array where the array element values are >= 3.

F#
let arrayOf10 = [|0..10|]
let tupleResults = Array.partition (fun element -> element < 3) arrayOf10
    
printfn "let arrayOf10 = [|0..10|]"
printfn "let tupleResults = Array.partition (fun element -> element < 3) arrayOf10"
printfn "tupleResults fst = %A" (tupleResults |> fst)
printfn "tupleResults snd = %A" (tupleResults |> snd)

Which when run produces the following results:

image

This article was originally posted at http://sachabarbs.wordpress.com/2014/03/28/f12-arrays

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United Kingdom United Kingdom
I currently hold the following qualifications (amongst others, I also studied Music Technology and Electronics, for my sins)

- MSc (Passed with distinctions), in Information Technology for E-Commerce
- BSc Hons (1st class) in Computer Science & Artificial Intelligence

Both of these at Sussex University UK.

Award(s)

I am lucky enough to have won a few awards for Zany Crazy code articles over the years

  • Microsoft C# MVP 2016
  • Codeproject MVP 2016
  • Microsoft C# MVP 2015
  • Codeproject MVP 2015
  • Microsoft C# MVP 2014
  • Codeproject MVP 2014
  • Microsoft C# MVP 2013
  • Codeproject MVP 2013
  • Microsoft C# MVP 2012
  • Codeproject MVP 2012
  • Microsoft C# MVP 2011
  • Codeproject MVP 2011
  • Microsoft C# MVP 2010
  • Codeproject MVP 2010
  • Microsoft C# MVP 2009
  • Codeproject MVP 2009
  • Microsoft C# MVP 2008
  • Codeproject MVP 2008
  • And numerous codeproject awards which you can see over at my blog

Comments and Discussions

 
-- There are no messages in this forum --