# Arrays

Note

The API reference link will take you to MSDN. The docs.microsoft.com API reference is not complete.

Arrays are fixed-size, zero-based, mutable collections of consecutive data elements that are all of the same type.

## Creating Arrays

You can create arrays in several ways. You can create a small array by listing consecutive values between `[|`

and `|]`

and separated by semicolons, as shown in the following examples.

```
let array1 = [| 1; 2; 3 |]
```

You can also put each element on a separate line, in which case the semicolon separator is optional.

```
let array1 =
[|
1
2
3
|]
```

The type of the array elements is inferred from the literals used and must be consistent. The following code causes an error because 1.0 is a float and 2 and 3 are integers.

```
// Causes an error.
// let array2 = [| 1.0; 2; 3 |]
```

You can also use sequence expressions to create arrays. Following is an example that creates an array of squares of integers from 1 to 10.

```
let array3 = [| for i in 1 .. 10 -> i * i |]
```

To create an array in which all the elements are initialized to zero, use `Array.zeroCreate`

.

```
let arrayOfTenZeroes : int array = Array.zeroCreate 10
```

## Accessing Elements

You can access array elements by using a dot operator (`.`

) and brackets (`[`

and `]`

).

```
array1.[0]
```

Array indexes start at 0.

You can also access array elements by using slice notation, which enables you to specify a subrange of the array. Examples of slice notation follow.

```
// Accesses elements from 0 to 2.
array1.[0..2]
// Accesses elements from the beginning of the array to 2.
array1.[..2]
// Accesses elements from 2 to the end of the array.
array1.[2..]
```

When slice notation is used, a new copy of the array is created.

## Array Types and Modules

The type of all F# arrays is the .NET Framework type System.Array. Therefore, F# arrays support all the functionality available in System.Array.

The library module `Microsoft.FSharp.Collections.Array`

supports operations on one-dimensional arrays. The modules `Array2D`

, `Array3D`

, and `Array4D`

contain functions that support operations on arrays of two, three, and four dimensions, respectively. You can create arrays of rank greater than four by using System.Array.

### Simple Functions

`Array.get`

gets an element. `Array.length`

gives the length of an array. `Array.set`

sets an element to a specified value. The following code example illustrates the use of these functions.

```
let array1 = Array.create 10 ""
for i in 0 .. array1.Length - 1 do
Array.set array1 i (i.ToString())
for i in 0 .. array1.Length - 1 do
printf "%s " (Array.get array1 i)
```

The output is as follows.

```
0 1 2 3 4 5 6 7 8 9
```

### Functions That Create Arrays

Several functions create arrays without requiring an existing array. `Array.empty`

creates a new array that does not contain any elements. `Array.create`

creates an array of a specified size and sets all the elements to provided values. `Array.init`

creates an array, given a dimension and a function to generate the elements. `Array.zeroCreate`

creates an array in which all the elements are initialized to the zero value for the array's type. The following code demonstrates these functions.

```
let myEmptyArray = Array.empty
printfn "Length of empty array: %d" myEmptyArray.Length
printfn "Array of floats set to 5.0: %A" (Array.create 10 5.0)
printfn "Array of squares: %A" (Array.init 10 (fun index -> index * index))
let (myZeroArray : float array) = Array.zeroCreate 10
```

The output is as follows.

```
Length of empty array: 0
Area of floats set to 5.0: [|5.0; 5.0; 5.0; 5.0; 5.0; 5.0; 5.0; 5.0; 5.0; 5.0|]
Array of squares: [|0; 1; 4; 9; 16; 25; 36; 49; 64; 81|]
```

`Array.copy`

creates a new array that contains elements that are copied from an existing array. Note that the copy is a shallow copy, which means that if the element type is a reference type, only the reference is copied, not the underlying object. The following code example illustrates this.

```
open System.Text
let firstArray : StringBuilder array = Array.init 3 (fun index -> new StringBuilder(""))
let secondArray = Array.copy firstArray
// Reset an element of the first array to a new value.
firstArray.[0] <- new StringBuilder("Test1")
// Change an element of the first array.
firstArray.[1].Insert(0, "Test2") |> ignore
printfn "%A" firstArray
printfn "%A" secondArray
```

The output of the preceding code is as follows:

```
[|Test1; Test2; |]
[|; Test2; |]
```

The string `Test1`

appears only in the first array because the operation of creating a new element overwrites the reference in `firstArray`

but does not affect the original reference to an empty string that is still present in `secondArray`

. The string `Test2`

appears in both arrays because the `Insert`

operation on the System.Text.StringBuilder type affects the underlying System.Text.StringBuilder object, which is referenced in both arrays.

`Array.sub`

generates a new array from a subrange of an array. You specify the subrange by providing the starting index and the length. The following code demonstrates the use of `Array.sub`

.

```
let a1 = [| 0 .. 99 |]
let a2 = Array.sub a1 5 10
printfn "%A" a2
```

The output shows that the subarray starts at element 5 and contains 10 elements.

```
[|5; 6; 7; 8; 9; 10; 11; 12; 13; 14|]
```

`Array.append`

creates a new array by combining two existing arrays.

The following code demonstrates **Array.append**.

```
printfn "%A" (Array.append [| 1; 2; 3|] [| 4; 5; 6|])
```

The output of the preceding code is as follows.

```
[|1; 2; 3; 4; 5; 6|]
```

`Array.choose`

selects elements of an array to include in a new array. The following code demonstrates `Array.choose`

. Note that the element type of the array does not have to match the type of the value returned in the option type. In this example, the element type is `int`

and the option is the result of a polynomial function, `elem*elem - 1`

, as a floating point number.

```
printfn "%A" (Array.choose (fun elem -> if elem % 2 = 0 then
Some(float (elem*elem - 1))
else
None) [| 1 .. 10 |])
```

The output of the preceding code is as follows.

```
[|3.0; 15.0; 35.0; 63.0; 99.0|]
```

`Array.collect`

runs a specified function on each array element of an existing array and then collects the elements generated by the function and combines them into a new array. The following code demonstrates `Array.collect`

.

```
printfn "%A" (Array.collect (fun elem -> [| 0 .. elem |]) [| 1; 5; 10|])
```

The output of the preceding code is as follows.

```
[|0; 1; 0; 1; 2; 3; 4; 5; 0; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10|]
```

`Array.concat`

takes a sequence of arrays and combines them into a single array. The following code demonstrates `Array.concat`

.

```
Array.concat [ [|0..3|] ; [|4|] ]
//output [|0; 1; 2; 3; 4|]
Array.concat [| [|0..3|] ; [|4|] |]
//output [|0; 1; 2; 3; 4|]
```

The output of the preceding code is as follows.

```
[|(1, 1, 1); (1, 2, 2); (1, 3, 3); (2, 1, 2); (2, 2, 4); (2, 3, 6); (3, 1, 3);
(3, 2, 6); (3, 3, 9)|]
```

`Array.filter`

takes a Boolean condition function and generates a new array that contains only those elements from the input array for which the condition is true. The following code demonstrates `Array.filter`

.

```
printfn "%A" (Array.filter (fun elem -> elem % 2 = 0) [| 1 .. 10|])
```

The output of the preceding code is as follows.

```
[|2; 4; 6; 8; 10|]
```

`Array.rev`

generates a new array by reversing the order of an existing array. The following code demonstrates `Array.rev`

.

```
let stringReverse (s: string) =
System.String(Array.rev (s.ToCharArray()))
printfn "%A" (stringReverse("!dlrow olleH"))
```

The output of the preceding code is as follows.

```
"Hello world!"
```

You can easily combine functions in the array module that transform arrays by using the pipeline operator (`|>`

), as shown in the following example.

```
[| 1 .. 10 |]
|> Array.filter (fun elem -> elem % 2 = 0)
|> Array.choose (fun elem -> if (elem <> 8) then Some(elem*elem) else None)
|> Array.rev
|> printfn "%A"
```

The output is

```
[|100; 36; 16; 4|]
```

### Multidimensional Arrays

A multidimensional array can be created, but there is no syntax for writing a multidimensional array literal. Use the operator `array2D`

to create an array from a sequence of sequences of array elements. The sequences can be array or list literals. For example, the following code creates a two-dimensional array.

```
let my2DArray = array2D [ [ 1; 0]; [0; 1] ]
```

You can also use the function `Array2D.init`

to initialize arrays of two dimensions, and similar functions are available for arrays of three and four dimensions. These functions take a function that is used to create the elements. To create a two-dimensional array that contains elements set to an initial value instead of specifying a function, use the `Array2D.create`

function, which is also available for arrays up to four dimensions. The following code example first shows how to create an array of arrays that contain the desired elements, and then uses `Array2D.init`

to generate the desired two-dimensional array.

```
let arrayOfArrays = [| [| 1.0; 0.0 |]; [|0.0; 1.0 |] |]
let twoDimensionalArray = Array2D.init 2 2 (fun i j -> arrayOfArrays.[i].[j])
```

Array indexing and slicing syntax is supported for arrays up to rank 4. When you specify an index in multiple dimensions, you use commas to separate the indexes, as illustrated in the following code example.

```
twoDimensionalArray.[0, 1] <- 1.0
```

The type of a two-dimensional array is written out as `<type>[,]`

(for example, `int[,]`

, `double[,]`

), and the type of a three-dimensional array is written as `<type>[,,]`

, and so on for arrays of higher dimensions.

Only a subset of the functions available for one-dimensional arrays is also available for multidimensional arrays. For more information, see `Collections.Array Module`

, `Collections.Array2D Module`

, `Collections.Array3D Module`

, and `Collections.Array4D Module`

.

### Array Slicing and Multidimensional Arrays

In a two-dimensional array (a matrix), you can extract a sub-matrix by specifying ranges and using a wildcard (`*`

) character to specify whole rows or columns.

```
/ Get rows 1 to N from an NxM matrix (returns a matrix):
matrix.[1.., *]
// Get rows 1 to 3 from a matrix (returns a matrix):
matrix.[1..3, *]
// Get columns 1 to 3 from a matrix (returns a matrix):
matrix.[*, 1..3]
// Get a 3x3 submatrix:
matrix.[1..3, 1..3]
```

As of F# 3.1, you can decompose a multidimensional array into subarrays of the same or lower dimension. For example, you can obtain a vector from a matrix by specifying a single row or column.

```
// Get row 3 from a matrix as a vector:
matrix.[3, *]
// Get column 3 from a matrix as a vector:
matrix.[*, 3]
```

You can use this slicing syntax for types that implement the element access operators and overloaded `GetSlice`

methods. For example, the following code creates a Matrix type that wraps the F# 2D array, implements an Item property to provide support for array indexing, and implements three versions of `GetSlice`

. If you can use this code as a template for your matrix types, you can use all the slicing operations that this section describes.

```
type Matrix<'T>(N: int, M: int) =
let internalArray = Array2D.zeroCreate<'T> N M
member this.Item
with get(a: int, b: int) = internalArray.[a, b]
and set(a: int, b: int) (value:'T) = internalArray.[a, b] <- value
member this.GetSlice(rowStart: int option, rowFinish : int option, colStart: int option, colFinish : int option) =
let rowStart =
match rowStart with
| Some(v) -> v
| None -> 0
let rowFinish =
match rowFinish with
| Some(v) -> v
| None -> internalArray.GetLength(0) - 1
let colStart =
match colStart with
| Some(v) -> v
| None -> 0
let colFinish =
match colFinish with
| Some(v) -> v
| None -> internalArray.GetLength(1) - 1
internalArray.[rowStart..rowFinish, colStart..colFinish]
member this.GetSlice(row: int, colStart: int option, colFinish: int option) =
let colStart =
match colStart with
| Some(v) -> v
| None -> 0
let colFinish =
match colFinish with
| Some(v) -> v
| None -> internalArray.GetLength(1) - 1
internalArray.[row, colStart..colFinish]
member this.GetSlice(rowStart: int option, rowFinish: int option, col: int) =
let rowStart =
match rowStart with
| Some(v) -> v
| None -> 0
let rowFinish =
match rowFinish with
| Some(v) -> v
| None -> internalArray.GetLength(0) - 1
internalArray.[rowStart..rowFinish, col]
module test =
let generateTestMatrix x y =
let matrix = new Matrix<float>(3, 3)
for i in 0..2 do
for j in 0..2 do
matrix.[i, j] <- float(i) * x - float(j) * y
matrix
let test1 = generateTestMatrix 2.3 1.1
let submatrix = test1.[0..1, 0..1]
printfn "%A" submatrix
let firstRow = test1.[0,*]
let secondRow = test1.[1,*]
let firstCol = test1.[*,0]
printfn "%A" firstCol
```

### Boolean Functions on Arrays

The functions `Array.exists`

and `Array.exists2`

test elements in either one or two arrays, respectively. These functions take a test function and return `true`

if there is an element (or element pair for `Array.exists2`

) that satisfies the condition.

The following code demonstrates the use of `Array.exists`

and `Array.exists2`

. In these examples, new functions are created by applying only one of the arguments, in these cases, the function argument.

```
let allNegative = Array.exists (fun elem -> abs (elem) = elem) >> not
printfn "%A" (allNegative [| -1; -2; -3 |])
printfn "%A" (allNegative [| -10; -1; 5 |])
printfn "%A" (allNegative [| 0 |])
let haveEqualElement = Array.exists2 (fun elem1 elem2 -> elem1 = elem2)
printfn "%A" (haveEqualElement [| 1; 2; 3 |] [| 3; 2; 1|])
```

The output of the preceding code is as follows.

```
true
false
false
true
```

Similarly, the function `Array.forall`

tests an array to determine whether every element satisfies a Boolean condition. The variation `Array.forall2`

does the same thing by using a Boolean function that involves elements of two arrays of equal length. The following code illustrates the use of these functions.

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

The output for these examples is as follows.

```
false
true
true
false
```

### Searching Arrays

`Array.find`

takes a Boolean function and returns the first element for which the function returns `true`

, or raises a System.Collections.Generic.KeyNotFoundException if no element that satisfies the condition is found. `Array.findIndex`

is like `Array.find`

, except that it returns the index of the element instead of the element itself.

The following code uses `Array.find`

and `Array.findIndex`

to locate a number that is both a perfect square and perfect cube.

```
let arrayA = [| 2 .. 100 |]
let delta = 1.0e-10
let isPerfectSquare (x:int) =
let y = sqrt (float x)
abs(y - round y) < delta
let isPerfectCube (x:int) =
let y = System.Math.Pow(float x, 1.0/3.0)
abs(y - round y) < delta
let element = Array.find (fun elem -> isPerfectSquare elem && isPerfectCube elem) arrayA
let index = Array.findIndex (fun elem -> isPerfectSquare elem && isPerfectCube elem) arrayA
printfn "The first element that is both a square and a cube is %d and its index is %d." element index
```

The output is as follows.

```
The first element that is both a square and a cube is 64 and its index is 62.
```

`Array.tryFind`

is like `Array.find`

, except that its result is an option type, and it returns `None`

if no element is found. `Array.tryFind`

should be used instead of `Array.find`

when you do not know whether a matching element is in the array. Similarly, `Array.tryFindIndex`

is like `Array.findIndex`

except that the option type is the return value. If no element is found, the option is `None`

.

The following code demonstrates the use of `Array.tryFind`

. This code depends on the previous code.

```
let delta = 1.0e-10
let isPerfectSquare (x:int) =
let y = sqrt (float x)
abs(y - round y) < delta
let isPerfectCube (x:int) =
let y = System.Math.Pow(float x, 1.0/3.0)
abs(y - round y) < delta
let lookForCubeAndSquare array1 =
let result = Array.tryFind (fun elem -> isPerfectSquare elem && isPerfectCube elem) array1
match result with
| Some x -> printfn "Found an element: %d" x
| None -> printfn "Failed to find a matching element."
lookForCubeAndSquare [| 1 .. 10 |]
lookForCubeAndSquare [| 100 .. 1000 |]
lookForCubeAndSquare [| 2 .. 50 |]
```

The output is as follows.

```
Found an element: 1
Found an element: 729
```

Use `Array.tryPick`

when you need to transform an element in addition to finding it. The result is the first element for which the function returns the transformed element as an option value, or `None`

if no such element is found.

The following code shows the use of `Array.tryPick`

. In this case, instead of a lambda expression, several local helper functions are defined to simplify the code.

```
let findPerfectSquareAndCube array1 =
let delta = 1.0e-10
let isPerfectSquare (x:int) =
let y = sqrt (float x)
abs(y - round y) < delta
let isPerfectCube (x:int) =
let y = System.Math.Pow(float x, 1.0/3.0)
abs(y - round y) < delta
// intFunction : (float -> float) -> int -> int
// Allows the use of a floating point function with integers.
let intFunction function1 number = int (round (function1 (float number)))
let cubeRoot x = System.Math.Pow(x, 1.0/3.0)
// testElement: int -> (int * int * int) option
// Test an element to see whether it is a perfect square and a perfect
// cube, and, if so, return the element, square root, and cube root
// as an option value. Otherwise, return None.
let testElement elem =
if isPerfectSquare elem && isPerfectCube elem then
Some(elem, intFunction sqrt elem, intFunction cubeRoot elem)
else None
match Array.tryPick testElement array1 with
| Some (n, sqrt, cuberoot) -> printfn "Found an element %d with square root %d and cube root %d." n sqrt cuberoot
| None -> printfn "Did not find an element that is both a perfect square and a perfect cube."
findPerfectSquareAndCube [| 1 .. 10 |]
findPerfectSquareAndCube [| 2 .. 100 |]
findPerfectSquareAndCube [| 100 .. 1000 |]
findPerfectSquareAndCube [| 1000 .. 10000 |]
findPerfectSquareAndCube [| 2 .. 50 |]
```

The output is as follows.

```
Found an element 1 with square root 1 and cube root 1.
Found an element 64 with square root 8 and cube root 4.
Found an element 729 with square root 27 and cube root 9.
Found an element 4096 with square root 64 and cube root 16.
```

### Performing Computations on Arrays

The `Array.average`

function returns the average of each element in an array. It is limited to element types that support exact division by an integer, which includes floating point types but not integral types. The `Array.averageBy`

function returns the average of the results of calling a function on each element. For an array of integral type, you can use `Array.averageBy`

and have the function convert each element to a floating point type for the computation.

Use `Array.max`

or `Array.min`

to get the maximum or minimum element, if the element type supports it. Similarly, `Array.maxBy`

and `Array.minBy`

allow a function to be executed first, perhaps to transform to a type that supports comparison.

`Array.sum`

adds the elements of an array, and `Array.sumBy`

calls a function on each element and adds the results together.

To execute a function on each element in an array without storing the return values, use `Array.iter`

. For a function involving two arrays of equal length, use `Array.iter2`

. If you also need to keep an array of the results of the function, use `Array.map`

or `Array.map2`

, which operates on two arrays at a time.

The variations `Array.iteri`

and `Array.iteri2`

allow the index of the element to be involved in the computation; the same is true for `Array.mapi`

and `Array.mapi2`

.

The functions `Array.fold`

, `Array.foldBack`

, `Array.reduce`

, `Array.reduceBack`

, `Array.scan`

, and `Array.scanBack`

execute algorithms that involve all the elements of an array. Similarly, the variations `Array.fold2`

and `Array.foldBack2`

perform computations on two arrays.

These functions for performing computations correspond to the functions of the same name in the List module. For usage examples, see Lists.

### Modifying Arrays

`Array.set`

sets an element to a specified value. `Array.fill`

sets a range of elements in an array to a specified value. The following code provides an example of `Array.fill`

.

```
let arrayFill1 = [| 1 .. 25 |]
Array.fill arrayFill1 2 20 0
printfn "%A" arrayFill1
```

The output is as follows.

```
[|1; 2; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 23; 24; 25|]
```

You can use `Array.blit`

to copy a subsection of one array to another array.

### Converting to and from Other Types

`Array.ofList`

creates an array from a list. `Array.ofSeq`

creates an array from a sequence. `Array.toList`

and `Array.toSeq`

convert to these other collection types from the array type.

### Sorting Arrays

Use `Array.sort`

to sort an array by using the generic comparison function. Use `Array.sortBy`

to specify a function that generates a value, referred to as a *key*, to sort by using the generic comparison function on the key. Use `Array.sortWith`

if you want to provide a custom comparison function. `Array.sort`

, `Array.sortBy`

, and `Array.sortWith`

all return the sorted array as a new array. The variations `Array.sortInPlace`

, `Array.sortInPlaceBy`

, and `Array.sortInPlaceWith`

modify the existing array instead of returning a new one.

### Arrays and Tuples

The functions `Array.zip`

and `Array.unzip`

convert arrays of tuple pairs to tuples of arrays and vice versa. `Array.zip3`

and `Array.unzip3`

are similar except that they work with tuples of three elements or tuples of three arrays.

## Parallel Computations on Arrays

The module `Array.Parallel`

contains functions for performing parallel computations on arrays. This module is not available in applications that target versions of the .NET Framework prior to version 4.

## See also

## Feedback

We'd love to hear your thoughts. Choose the type you'd like to provide:

Our feedback system is built on GitHub Issues. Read more on our blog.

Loading feedback...