共用方式為


陣列 (F#)

陣列是固定大小、以零起始、可變動的連續數據元素集合,這些集合全都屬於相同類型。

建立陣列

您可以透過數種方式建立數位。 您可以藉由列出 和 |] 之間的[|連續值和以分號分隔來建立小型陣列,如下列範例所示。

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

您也可以將每個元素放在個別的行上,在此情況下,分號分隔符是選擇性的。

let array1 =
    [|
        1
        2
        3
     |]

陣列元素的類型是從使用的常值推斷而來,而且必須一致。

// This is an array of 3 integers.
let array1 = [| 1; 2; 3 |]
// This is an array of a tuple of 3 integers.
let array2 = [| 1, 2, 3 |]

下列程式代碼會造成錯誤,因為 3.0 是浮點數,而 1 和 2 是整數。

// Causes an error. The 3.0 (float) cannot be converted to integer implicitly.
// let array3 = [| 1; 2; 3.0 |]

下列程式代碼也會造成錯誤,因為 1,2 是 Tuple 且 3 是整數。

// Causes an error too. The 3 (integer) cannot be converted to tuple implicitly.
// let array4 = [| 1, 2; 3 |]

您也可以使用時序表示式來建立數位。 以下是從 1 到 10 建立整數平方陣列的範例。

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

若要建立陣列,其中所有項目都會初始化為零,請使用 Array.zeroCreate

let arrayOfTenZeroes : int array = Array.zeroCreate 10

Access 元素

您可以使用方括弧 ([]) 來存取陣列元素。 原始點語法 (.[index]) 仍受到支援,但從 F# 6.0 起不再建議使用。

array1[0]

陣列索引從 0 開始。

您也可以使用配量表示法來存取數位元素,這可讓您指定陣列的子範圍。 配量表示法的范例如下。

// 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..]

使用配量表示法時,會建立數位的新複本。

數位型別和模組

所有 F# 陣列的類型都是 .NET Framework 類型 System.Array。 因此,F# 陣列支援 中 System.Array所有可用的功能。

模組Array支援一維陣列上的作業。 模組 Array2DArray3DArray4D 包含分別支援兩個、三個和四個維度陣列作業的函式。 您可以使用 來建立排名大於四 System.Array的陣列。

簡單函式

Array.get 取得專案。 Array.length 提供陣列的長度。 Array.set 將項目設定為指定的值。 下列程式代碼範例說明如何使用這些函式。

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)

輸出如下。

0 1 2 3 4 5 6 7 8 9

建立數位的函式

數個函式會建立陣列,而不需要現有的陣列。 Array.empty 會建立不包含任何專案的新陣列。 Array.create 會建立指定大小的陣列,並將所有元素設定為提供的值。 Array.init 會建立數位,指定維度和函式來產生專案。 Array.zeroCreate 會建立數位,其中所有項目都會初始化為數位類型的零值。 下列程式代碼示範這些函式。

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

輸出如下。

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 會建立新的陣列,其中包含從現有數位複製的專案。 請注意,複製是淺層複本,這表示如果專案類型是參考型別,則只會複製參考,而不是基礎物件。 下列程式代碼範例說明這點。

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

上述程式代碼的輸出如下所示:

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

字串 Test1 只會出現在第一個陣列中,因為建立新項目的作業會覆寫 中的 firstArray 參考,但不會影響原始參考中仍存在於中的 secondArray空字串。 字串 Test2 會出現在這兩個陣列中,因為 Insert 型別上的 System.Text.StringBuilder 作業會影響基礎 System.Text.StringBuilder 物件,這兩個陣列中都會參考此物件。

Array.sub 從數位的子範圍產生新的數位。 您可以藉由提供起始索引和長度來指定子範圍。 下列程式代碼示範 如何使用 Array.sub

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

輸出顯示子陣列從元素 5 開始,並包含 10 個專案。

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

Array.append 結合兩個現有的陣列來建立新的數位。

下列程式代碼示範 Array.append

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

上述程式代碼的輸出如下所示。

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

Array.choose 會選取要包含在新陣列中的陣列元素。 下列程式代碼示範 Array.choose。 請注意,陣列的元素類型不一定符合選項類型中傳回的值類型。 在此範例中,元素類型是 int ,而 選項是多項式函式的結果, elem*elem - 1做為浮點數。

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

上述程式代碼的輸出如下所示。

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

Array.collect 在現有數位的每個數位元素上執行指定的函式,然後收集函式所產生的專案,並將其合併成新的陣列。 下列程式代碼示範 Array.collect

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

上述程式代碼的輸出如下所示。

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

Array.concat 會採用數位序列,並將其合併成單一陣列。 下列程式代碼示範 Array.concat

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

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

Array.filter 會採用布爾條件函式,併產生新的數位,其中只包含條件為 true 之輸入數位中的元素。 下列程式代碼示範 Array.filter

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

上述程式代碼的輸出如下所示。

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

Array.rev 藉由反轉現有數位的順序來產生新的陣列。 下列程式代碼示範 Array.rev

let stringReverse (s: string) =
    System.String(Array.rev (s.ToCharArray()))

printfn "%A" (stringReverse("!dlrow olleH"))

上述程式代碼的輸出如下所示。

"Hello world!"

您可以使用管線運算符 (|>), 輕鬆地結合數位塊中的函式,如下列範例所示。

[| 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"

輸出為

[|100; 36; 16; 4|]

多維陣列

可以建立多維度陣列,但沒有語法可撰寫多維度陣列常值。 使用 運算子 array2D ,從陣列建立陣列建立陣列。 序列可以是陣列或清單常值。 例如,下列程式代碼會建立二維陣列。

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

您也可以使用 函 Array2D.init 式來初始化兩個維度的陣列,而類似的函式適用於三個和四個維度的陣列。 這些函式會採用用來建立元素的函式。 若要建立二維數位,其中包含設定為初始值的專案,而不是指定函式,請使用 Array2D.create 函式,此函式也適用於最多四個維度的數位。 下列程式代碼範例會先示範如何建立包含所需元素的陣列數位列列,然後使用 Array2D.init 來產生所需的二維陣列。

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

數位的索引編製和配量語法最多支援排名 4 的陣列。 當您在多個維度中指定索引時,您可以使用逗號來分隔索引,如下列程式代碼範例所示。

twoDimensionalArray[0, 1] <- 1.0

二維陣列的類型會寫成 <type>[,] (例如 , int[,]double[,]),而三維數位列的類型會寫入為 <type>[,,],依此類寫為較高維度的陣列。

只有一維數位列可用的函式子集也可用於多維度陣列。

陣列配量和多維度陣列

在二維陣列(矩陣)中,您可以指定範圍並使用通配符 (*) 字元來指定整個數據列或數據行,以擷取子矩陣。

// 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]

您可以將多維度陣列分解成相同或較低維度的子陣列。 例如,您可以藉由指定單一數據列或數據行,從矩陣取得向量。

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

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

您可以針對實作元素存取運算子和多載 GetSlice 方法的類型使用此切割語法。 例如,下列程式代碼會建立一個矩陣類型來包裝 F# 2D 陣列、實作 Item 屬性以提供陣列索引的支援,以及實作三個 GetSlice版本的 。 如果您可以使用此程式代碼作為矩陣類型的範本,您可以使用本節描述的所有切割作業。

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 $"{submatrix}"

    let firstRow = test1[0,*]
    let secondRow = test1[1,*]
    let firstCol = test1[*,0]
    printfn $"{firstCol}"

陣列上的布爾函數

一或兩個陣列中的函 Array.exists 式和 Array.exists2 測試元素分別。 這些函式會接受測試函式,並在有符合條件的專案(或專案組Array.exists2)時傳回 true

下列程式代碼示範和Array.exists2的使用Array.exists。 在這些範例中,新函式只會套用其中一個自變數來建立,在這些案例中為函式自變數。

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|])

上述程式代碼的輸出如下所示。

true
false
false
true

同樣地,函式 Array.forall 會測試陣列,以判斷每個元素是否符合布爾值條件。 此變化 Array.forall2 會使用包含兩個相同長度數位元素的布爾函式執行相同動作。 下列程式代碼說明如何使用這些函式。

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 |])

這些範例的輸出如下所示。

false
true
true
false

搜尋數位

Array.find 會採用 Boolean 函式,並傳回函式傳回 true的第一個元素,如果找不到符合條件的專案,則引發 System.Collections.Generic.KeyNotFoundExceptionArray.findIndex 就像 Array.find,不同之處在於它會傳回專案的索引,而不是專案本身。

下列程式代碼會使用 Array.findArray.findIndex 來找出一個既是完美正方形又完美的 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 first element that is both a square and a cube is 64 and its index is 62.

Array.tryFind 就像 Array.find,不同之處在於其結果為選項類型,如果找不到任何專案,則會傳 None 回 。 Array.tryFind 當您不知道相符的專案是否在陣列中時,應該使用 而不是 Array.find 。 同樣地, Array.tryFindIndex 就像 Array.findIndex 選項類型是傳回值。 如果找不到任何專案,則選項為 None

下列程式代碼示範 如何使用 Array.tryFind。 此程式代碼取決於先前的程序代碼。

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 |]

輸出如下。

Found an element: 1
Found an element: 729
Failed to find a matching element.

Array.tryPick當您除了尋找元素之外,還需要轉換項目時使用 。 結果是函式傳回已轉換專案做為選項值的第一個專案,如果 None 找不到這類專案,則為 。

下列程式代碼顯示 的 Array.tryPick用法。 在此情況下,會定義數個本機協助程式函式來簡化程序代碼,而不是 Lambda 表達式。

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 |]

輸出如下。

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.
Did not find an element that is both a perfect square and a perfect cube.

在陣列上執行計算

Array.average 式會傳回數位中每個專案的平均值。 它僅限於支援以整數進行完全除法的項目類型,其中包括浮點類型,但不包括整數型別。 函 Array.averageBy 式會傳回在每個元素上呼叫函式的結果平均值。 對於整數型別的陣列,您可以使用 Array.averageBy 和 讓函式將每個元素轉換成計算的浮點類型。

如果項目類型支援,請使用 Array.maxArray.min 取得最大或最小專案。 同樣地, Array.maxBy 並允許 Array.minBy 先執行函式,或許可以轉換成支持比較的類型。

Array.sum 會加入數位的專案,並在 Array.sumBy 每個元素上呼叫函式,並將結果一起加入。

若要在陣列中的每個項目上執行函式,而不儲存傳回值,請使用 Array.iter。 對於涉及兩個長度相等數位的函式,請使用 Array.iter2。 如果您也需要保留函式結果的陣列,請使用 Array.mapArray.map2,一次在兩個陣列上運作。

變化 Array.iteri 並允許 Array.iteri2 專案索引參與計算; Array.mapiArray.mapi2也是如此。

Array.fold包含數位所有元素的函式、Array.foldBackArray.reduce、、Array.reduceBackArray.scanArray.scanBack 執行演算法。 同樣地,變化 Array.fold2Array.foldBack2 在兩個陣列上執行計算。

這些用於執行計算的函式會對應至 List 模組中相同名稱的函式。 如需使用範例,請參閱 清單

修改陣列

Array.set 將項目設定為指定的值。 Array.fill 將陣列中的項目範圍設定為指定的值。 下列程式代碼提供的 Array.fill範例。

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

輸出如下。

[|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|]

您可以使用 Array.blit 將某個陣列的子區段複製到另一個數位列。

從其他類型來回轉換

Array.ofList 從清單中建立陣列。 Array.ofSeq 從序列建立陣列。 Array.toListArray.toSeq 會從數位類型轉換成這些其他集合類型。

排序陣列

使用 Array.sort 來使用泛型比較函式來排序數位列。 使用 Array.sortBy 來指定產生值,稱為 索引鍵的函式,以使用索引鍵上的泛型比較函式進行排序。 如果您要提供自訂比較函式,請使用 Array.sortWithArray.sortArray.sortByArray.sortWith 都傳回已排序的陣列做為新的數位。 變化 Array.sortInPlaceArray.sortInPlaceByArray.sortInPlaceWith 會修改現有的陣列,而不是傳回新的數位。

陣列和 Tuple

Array.zip函式和Array.unzip將 Tuple 配對的數位轉換成陣列的 Tuple,反之亦然。 Array.zip3Array.unzip3 很類似,不同之處在於它們使用三個元素的 Tuple 或三個陣列的 Tuple。

陣列上的平行計算

模組 Array.Parallel 包含在數位上執行平行計算的函式。 此模組不適用於以第 4 版之前 .NET Framework 版本為目標的應用程式。

另請參閱