Segmenten

In dit artikel wordt uitgelegd hoe u segmenten van bestaande F#-typen kunt gebruiken en hoe u uw eigen segmenten definieert.

In F# is een segment een subset van elk gegevenstype. Segmenten zijn vergelijkbaar met indexeerfuncties, maar in plaats van één waarde op te geven uit de onderliggende gegevensstructuur, leveren ze meerdere waarden op. Segmenten gebruiken de .. operatorsyntaxis om het bereik van opgegeven indexen in een gegevenstype te selecteren. Zie het naslagartikel over de lusexpressie voor meer informatie.

F# biedt momenteel intrinsieke ondersteuning voor segmenteringstekenreeksen, lijsten, matrices en multidimensionale matrices (2D, 3D, 4D). Segmentering wordt meestal gebruikt met F#-matrices en -lijsten. U kunt segmentering toevoegen aan uw aangepaste gegevenstypen met behulp van de GetSlice methode in uw typedefinitie of in een extensie voor het bereiktype.

F#-lijsten en matrices segmenteren

De meest voorkomende gegevenstypen die worden gesegmenteerd, zijn F#-lijsten en matrices. In het volgende voorbeeld ziet u hoe u lijsten segmenteert:

// 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}"

Segmenteringsmatrices zijn net als segmenteringslijsten:

// 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}"

Vóór F# 6 gebruikte segmentering de syntaxis expr.[start..finish] met de extra .. Als u kiest, kunt u deze syntaxis nog steeds gebruiken. Zie RFC FS-1110 voor meer informatie.

Multidimensionale matrices segmenteren

F# ondersteunt multidimensionale matrices in de F#-kernbibliotheek. Net als bij eendimensionale matrices kunnen segmenten van multidimensionale matrices ook nuttig zijn. De introductie van extra dimensies vereist echter een iets andere syntaxis, zodat u segmenten van specifieke rijen en kolommen kunt nemen.

In de volgende voorbeelden ziet u hoe u een 2D-matrix kunt segmenteren:

// 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}"

Segmenten definiëren voor andere gegevensstructuren

De F#-kernbibliotheek definieert segmenten voor een beperkte set typen. Als u segmenten wilt definiëren voor meer gegevenstypen, kunt u dit doen in de typedefinitie zelf of in een typeextensie.

U kunt bijvoorbeeld segmenten voor de ArraySegment<T> klasse definiëren om handige gegevensmanipulatie mogelijk te maken:

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]

Een ander voorbeeld met behulp van de Span<T> en ReadOnlySpan<T> typen:

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

Ingebouwde F#-segmenten zijn end-inclusive

Alle intrinsieke segmenten in F# zijn end-inclusive; Dat wil gezegd, de bovengrens is opgenomen in het segment. Voor een bepaald segment met beginindex en eindindex xybevat het resulterende segment de yth-waarde .

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

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

Ingebouwde lege F#-segmenten

F#-lijsten, matrices, reeksen, tekenreeksen, multidimensionale matrices (2D, 3D, 4D) produceren allemaal een leeg segment als de syntaxis een segment kan produceren dat niet bestaat.

Kijk een naar het volgende voorbeeld:

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

Belangrijk

C#-ontwikkelaars verwachten dat deze een uitzondering genereren in plaats van een leeg segment te produceren. Dit is een ontwerpbeslissing die is gebaseerd op het feit dat lege verzamelingen bestaan in F#. Een lege F#-lijst kan worden samengesteld met een andere F#-lijst, een lege tekenreeks kan worden toegevoegd aan een bestaande tekenreeks, enzovoort. Het kan gebruikelijk zijn om segmenten te nemen op basis van waarden die als parameters zijn doorgegeven en tolerant te zijn voor buitengrenswaarden > door een lege verzameling te produceren die past bij de samenstellingsaard van F#-code.

Segmenten met vaste index voor 3D- en 4D-matrices

Voor F# 3D- en 4D-matrices kunt u een bepaalde index 'herstellen' en andere dimensies segmenteren met die index vast.

Bekijk de volgende 3D-matrix om dit te illustreren:

z = 0

x\y 0 1
0 0 1
1 2 3

z = 1

x\y 0 1
0 4 5
1 6 7

Als u het segment [| 4; 5 |] uit de matrix wilt extraheren, gebruikt u een segment met vaste index.

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]

De laatste regel corrigeert de y en z indexen van de 3D-matrix en neemt de rest van de x waarden die overeenkomen met de matrix.

Zie ook