共用方式為


陣列 (F#)

陣列是固定大小、以零起始、可變的連續資料項目集合,而且所有項目的型別都相同。

建立陣列

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

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

您也可以將每個項目放在單獨一行,在此情況下,分號分隔符號為選擇性。

let array1 = 
    [|
        1
        2
        3
     |]

陣列元素的型別是從使用的常值來推斷,而且必須一致。因為 1.0 為浮點,而 2 和 3 為整數,所以下列程式碼會導致錯誤。

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

您也可以使用序列運算式來建立陣列。下列範例建立 1 到 10 之整數的平方陣列。

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

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

let arrayOfTenZeroes : int array = Array.zeroCreate 10

存取元素

您可以使用點運算子 (.) 和方括弧 ([ 和 ]) 存取陣列元素。

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 型別 Array。因此,F# 陣列支援 Array 中可用的所有功能。

程式庫模組 Microsoft.FSharp.Collections.Array 支援一維陣列的作業。模組 Array2DArray3DArray4D 包含的函式分別支援二維、三維和四維陣列的作業。您可以使用 Array 建立陣序大於四的陣列。

Dd233214.collapse_all(zh-tw,VS.110).gif簡單函式

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

Dd233214.collapse_all(zh-tw,VS.110).gif可建立陣列的函式

數個函式會建立陣列,而不需要現有的陣列。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 會出現在兩個陣列中,原因是 StringBuilder 型別上的 Insert 作業會影響基礎 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

let multiplicationTable max = seq { for i in 1 .. max -> [| for j in 1 .. max -> (i, j, i*j) |] }
printfn "%A" (Array.concat (multiplicationTable 3))

上述程式碼的輸出如下。

[|(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 採用布林條件函式,並產生新陣列,而這個陣列只包含符合條件之輸入陣列的那些項目。下列程式碼會示範 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|]

Dd233214.collapse_all(zh-tw,VS.110).gif多維陣列的比較

雖然可以建立多維陣列,但是沒有撰寫多維陣列常值的語法。使用運算子 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>[,,],更高維度的陣列以此類推。

一維陣列可用的函式只有部分可用於多維陣列。如需詳細資訊,請參閱 Collections.Array 模組 (F#)Collections.Array2D 模組 (F#)Collections.Array3D 模組 (F#)Collections.Array4D 模組 (F#)

Dd233214.collapse_all(zh-tw,VS.110).gif陣列的布林函式

Array.existsArray.exists2 函式會分別測試一個或兩個陣列中的項目。這些函式採用測試函式,並在有項目 (或 Array.exists2 的項目配對) 滿足條件時傳回 true。

下列程式碼會示範 Array.existsArray.exists2 的用法。在這些範例中,只套用其中一個引數來建立新函式,在這些情況下是函式引數。

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

Dd233214.collapse_all(zh-tw,VS.110).gif搜尋陣列

Array.find 採用布林函式,並傳回函式傳回 true 的第一個項目,如果找不到滿足條件的項目,則會引發 KeyNotFoundExceptionArray.findIndexArray.find 類似,差異在於它會傳回項目的索引,而非項目本身。

下列程式碼使用 Array.findArray.findIndex 尋找是完全平方也是完全立方的數字。

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.tryFindArray.find 類似,差異在於它會產生選項型別,並在找不到項目時傳回 None。當您不知道陣列中是否有相符項目時,應該使用 Array.tryFind,而非 Array.find。同樣地,Array.tryFindIndexArray.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

當您需要轉換和尋找項目時,請使用 Array.tryPick。如果函式傳回轉換後的元素做為選項值,則結果為第一個元素;如果找不到這類元素,則為 None。

下列程式碼顯示如何使用 Array.tryPick。在此情況下,已定義數種本機 Helper 函式來簡化程式碼,而非 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.

Dd233214.collapse_all(zh-tw,VS.110).gif對陣列執行計算

Array.average 函式會傳回陣列中各項目的平均值。而且限制為支援整數完全整除的項目型別,其包括浮點型別,而非整數型別。Array.averageBy 函式會傳回在每個項目上呼叫函式之結果的平均值。對於整數型別的陣列,您可以使用 Array.averageBy 讓函式將每個項目轉換為浮點型別以執行計算。

如果項目型別支援的話,請使用 Array.maxArray.min 取得最大或最小項目。同樣地,Array.maxByArray.minBy允許先執行函式,這可能會轉換為支援比較的型別。

Array.sum 會將陣列的項目相加,Array.sumBy 則會在每個項目上呼叫函式,並將結果相加。

若要在陣列的每個項目上執行函式,而不儲存傳回值,請使用 Array.iter。針對涉及兩個等長陣列的函式,請使用 Array.iter2。如果您也需要保留函式結果的陣列,請使用 Array.mapArray.map2 (其同時作用於兩個陣列)。

Array.iteriArray.iteri2 變化允許將項目的索引併入計算,而 Array.mapiArray.mapi2 也類似。

Array.foldArray.foldBackArray.reduceArray.reduceBackArray.scanArray.scanBack 函式會執行涉及陣列中所有項目的演算法。同樣地,Array.fold2Array.foldBack2 變化也會對兩個陣列執行計算。

這些執行計算的函式對應於清單模組中同名的函式。如需使用範例,請參閱清單 (F#)

Dd233214.collapse_all(zh-tw,VS.110).gif修改陣列

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 將某個陣列的子區段複製至另一個陣列。

Dd233214.collapse_all(zh-tw,VS.110).gif來回轉換成其他型別

Array.ofList 會透過清單建立陣列。Array.ofSeq 會透過序列建立陣列。Array.toListArray.toSeq 會從陣列型別轉換為其他集合型別。

Dd233214.collapse_all(zh-tw,VS.110).gif排序陣列

使用 Array.sort 可以透過泛型比較函式來排序陣列。使用 Array.sortBy 可以指定會產生值 (稱為「索引鍵」(Key)) 的函式,以針對索引鍵使用泛型比較函式來進行排序。如果您想要提供自訂比較函式,請使用 Array.sortWithArray.sortArray.sortByArray.sortWith 都會傳回已排序陣列做為新陣列。Array.sortInPlaceArray.sortInPlaceByArray.sortInPlaceWith 變化會修改現有陣列,而非傳回新陣列。

Dd233214.collapse_all(zh-tw,VS.110).gif陣列和 Tuple

Array.zipArray.unzip 函式會將 Tuple 配對的陣列轉換為陣列 Tuple,反之亦然。Array.zip3Array.unzip3 類似,差異在於它們會使用三個項目的 Tuple 或三個陣列的 Tuple。

陣列的平行計算

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

請參閱

其他資源

F# 語言參考

F# 型別