Dela via


Segment

Den här artikeln beskriver hur du tar sektorer från befintliga F#-typer och hur du definierar dina egna sektorer.

I F# är ett segment en delmängd av alla datatyper. Segment liknar indexerare, men i stället för att ge ett enda värde från den underliggande datastrukturen ger de flera. Segment använder operatorsyntaxen .. för att välja intervallet för angivna index i en datatyp. Mer information finns i referensartikeln för loopningsuttryck.

F# har för närvarande inbyggt stöd för att dela upp strängar, listor, matriser och flerdimensionella matriser (2D, 3D, 4D). Segmentering används oftast med F#-matriser och listor. Du kan lägga till segmentering i dina anpassade datatyper med hjälp GetSlice av metoden i din typdefinition eller i ett tillägg av typen in-scope.

Segmentera F#-listor och matriser

De vanligaste datatyperna som är segmenterade är F#-listor och matriser. I följande exempel visas hur du segmentera listor:

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

Segmentering av matriser är precis som segmenteringslistor:

// 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öre F# 6 använde segmentering syntaxen expr.[start..finish] med den extra .. Om du väljer kan du fortfarande använda den här syntaxen. Mer information finns i RFC FS-1110.

Segmentering av flerdimensionella matriser

F# stöder flerdimensionella matriser i F#-kärnbiblioteket. Precis som med endimensionella matriser kan sektorer av flerdimensionella matriser också vara användbara. Införandet av ytterligare dimensioner kräver dock en något annorlunda syntax så att du kan ta sektorer med specifika rader och kolumner.

Följande exempel visar hur du segmentera en 2D-matris:

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

Definiera sektorer för andra datastrukturer

F#-kärnbiblioteket definierar sektorer för en begränsad uppsättning typer. Om du vill definiera sektorer för fler datatyper kan du göra det antingen i själva typdefinitionen eller i ett typtillägg.

Så här kan du till exempel definiera sektorer för klassen för ArraySegment<T> att möjliggöra praktisk datamanipulering:

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]

Ett annat exempel med typerna Span<T> och 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|]

Inbyggda F#-sektorer är end-inclusive

Alla inbyggda sektorer i F# är end-inclusive; den övre gränsen ingår i sektorn. För en viss sektor med startindex x och slutindex yinnehåller den resulterande sektorn det y:e värdet.

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

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

Inbyggda F#-tomma sektorer

F#-listor, matriser, sekvenser, strängar, flerdimensionella matriser (2D, 3D, 4D) skapar alla en tom sektor om syntaxen kan skapa ett segment som inte finns.

Ta följande som exempel:

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

Viktigt!

C#-utvecklare kan förvänta sig att dessa utlöser ett undantag i stället för att skapa en tom sektor. Det här är ett designbeslut som bygger på att tomma samlingar består i F#. En tom F#-lista kan bestå av en annan F#-lista, en tom sträng kan läggas till i en befintlig sträng och så vidare. Det kan vara vanligt att ta sektorer baserat på värden som skickas som parametrar och vara toleranta mot out-of-bounds > genom att skapa en tom samling som passar med F#-kodens sammansättningskaraktär.

Segment med fast index för 3D- och 4D-matriser

För F# 3D- och 4D-matriser kan du "åtgärda" ett visst index och segmentera andra dimensioner med det indexet fast.

För att illustrera detta bör du överväga följande 3D-matris:

z = 0

x\y 0 1
0 0 1
1 2 3

z = 1

x\y 0 1
0 4 5
1 6 7

Om du vill extrahera sektorn [| 4; 5 |] från matrisen använder du en fast indexsektor.

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]

Den sista raden korrigerar indexen y och z för 3D-matrisen och tar resten av de x värden som motsvarar matrisen.

Se även