本文說明如何從現有的 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的指定配量,產生的配量會包含 yth 值。
// 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]
最後一行會修正 y 3D 陣列的 和 z 索引,並取得對應至矩陣的 x 其餘值。