Share via


配量

此文章說明如何從現有的 F# 類型取得配量,以及如何定義您自己的配量。

在 F# 中,配量是任何資料類型的子集。 配量類似於索引子,但不會從基礎資料結構產生單一值,而是會產生多個值。 配量會使用 .. 運算子語法來選取資料類型中指定之索引的範圍。 如需詳細資訊,請參閱迴圈運算式參考一文。

F# 目前內建支援配量字串、清單、陣列與多維度 (2D、3D、4D) 陣列。 配量最常搭配 F# 陣列與清單使用。 您可以使用類型定義或範圍內類型延伸模組中的 GetSlice 方法,將配量新增至您的自訂資料類型。

配量 F# 清單與陣列

配量的最常見資料類型是 F# 清單與陣列。 下列範例示範如何配量清單:

// Generate a list of 100 integers
let fullList = [ 1 .. 100 ]

// Create a slice from indices 1-5 (inclusive)
let smallSlice = fullList[1..5]
printfn $"Small slice: {smallSlice}"

// Create a slice from the beginning to index 5 (inclusive)
let unboundedBeginning = fullList[..5]
printfn $"Unbounded beginning slice: {unboundedBeginning}"

// Create a slice from an index to the end of the list
let unboundedEnd = fullList[94..]
printfn $"Unbounded end slice: {unboundedEnd}"

配量陣列就像配量清單:

// Generate an array of 100 integers
let fullArray = [| 1 .. 100 |]

// Create a slice from indices 1-5 (inclusive)
let smallSlice = fullArray[1..5]
printfn $"Small slice: {smallSlice}"

// Create a slice from the beginning to index 5 (inclusive)
let unboundedBeginning = fullArray[..5]
printfn $"Unbounded beginning slice: {unboundedBeginning}"

// Create a slice from an index to the end of the list
let unboundedEnd = fullArray[94..]
printfn $"Unbounded end slice: {unboundedEnd}"

在 F# 6 之前,配量會搭配額外的 . 使用語法 expr.[start..finish]。 如果您選擇,您仍然可以使用此語法。 如需詳細資訊,請參閱 RFC FS-1110

配量多維陣列

F# 在 F# 核心程式庫中支援多維陣列。 如同一維陣列,多維陣列的配量也很有用。 不過,引進其他維度會強制使用稍微不同的語法,讓您可以取得特定資料列與資料行的配量。

下列範例示範如何配量 2D 陣列:

// Generate a 3x3 2D matrix
let A = array2D [[1;2;3];[4;5;6];[7;8;9]]
printfn $"Full matrix:\n {A}"

// Take the first row
let row0 = A[0,*]
printfn $"{row0}"

// Take the first column
let col0 = A[*,0]
printfn $"{col0}"

// Take all rows but only two columns
let subA = A[*,0..1]
printfn $"{subA}"

// Take two rows and all columns
let subA' = A[0..1,*]
printfn $"{subA}"

// Slice a 2x2 matrix out of the full 3x3 matrix
let twoByTwo = A[0..1,0..1]
printfn $"{twoByTwo}"

定義其他資料結構的配量

F# 核心程式庫會定義一組有限類型的配量。 如果您想要定義更多資料類型的配量,可以在類型定義本身或類型延伸模組中進行。

例如,以下說明如何定義 ArraySegment<T> 類別的配量,以方便操作資料:

open System

type ArraySegment<'TItem> with
    member segment.GetSlice(start, finish) =
        let start = defaultArg start 0
        let finish = defaultArg finish segment.Count
        ArraySegment(segment.Array, segment.Offset + start, finish - start)

let arr = ArraySegment [| 1 .. 10 |]
let slice = arr[2..5] //[ 3; 4; 5]

使用 Span<T>ReadOnlySpan<T> 類型的另一個範例:

open System

type ReadOnlySpan<'T> with
    member sp.GetSlice(startIdx, endIdx) =
        let s = defaultArg startIdx 0
        let e = defaultArg endIdx sp.Length
        sp.Slice(s, e - s)

type Span<'T> with
    member sp.GetSlice(startIdx, endIdx) =
        let s = defaultArg startIdx 0
        let e = defaultArg endIdx sp.Length
        sp.Slice(s, e - s)

let printSpan (sp: Span<int>) =
    let arr = sp.ToArray()
    printfn $"{arr}"

let sp = [| 1; 2; 3; 4; 5 |].AsSpan()
printSpan sp[0..] // [|1; 2; 3; 4; 5|]
printSpan sp[..5] // [|1; 2; 3; 4; 5|]
printSpan sp[0..3] // [|1; 2; 3|]
printSpan sp[1..3] // |2; 3|]

內建的 F# 配量是包含結尾的

F# 中的所有內建配量都是包含結尾的;亦即,配量中包含上限。 針對具有起始索引 x 與結束索引 y 的指定配量,產生的配量會包含第 y 個值。

// Define a new list
let xs = [1 .. 10]

printfn $"{xs[2..5]}" // Includes the 5th index

內建的 F# 空配量

如果語法可能會產生不存在的配量,則 F# 清單、陣列、序列、字串、多維 (2D、3D、4D) 陣列全都會產生空配量。

請考慮下列範例:

let l = [ 1..10 ]
let a = [| 1..10 |]
let s = "hello!"

let emptyList = l[-2..(-1)]
let emptyArray = a[-2..(-1)]
let emptyString = s[-2..(-1)]

重要

C# 開發人員可能會希望這些項目擲回例外狀況,而不是產生空配量。 這是一個設計決策,根源在於空集合是以 F# 撰寫的。 空的 F# 清單可能與另一個 F# 清單一起撰寫、空字串可能新增至現有的字串等等。 根據當作參數傳入的值取得配量,並透過產生符合 F# 程式碼組合本質的空集合,以接受超出界限 > 的配量很常見。

3D 與 4D 陣列的固定索引配量

針對 F# 3D 與 4D 陣列,您可以「修正」特定索引,並在該索引固定的情況下,對其他維度配量。

為說明這一點,請考慮下列 3D 陣列︰

z = 0

x\y 0 1
0 0 1
1 2 3

z = 1

x\y 0 1
0 4 5
1 6 7

如果您想要從陣列擷取配量 [| 4; 5 |],請使用固定索引配量。

let dim = 2
let m = Array3D.zeroCreate<int> dim dim dim

let mutable count = 0

for z in 0..dim-1 do
    for y in 0..dim-1 do
        for x in 0..dim-1 do
            m[x,y,z] <- count
            count <- count + 1

// Now let's get the [4;5] slice!
m[*, 0, 1]

最後一行會修正 3D 陣列的 yz 索引,並取得對應至矩陣的其餘 x 值。

另請參閱