Freigeben über


Slices

In diesem Artikel wird erläutert, wie Sie Segmente von vorhandenen F#-Typen verwenden und eigene Segmente definieren.

In F# versteht man unter einem Segment eine Teilmenge eines Datentyps. Segmente ähneln Indexern, mit dem Unterschied, dass sie nicht nur einen einzigen Wert aus der zugrunde liegenden Datenstruktur ausgeben, sondern mehrere Werte. Segmente verwenden die Operatorsyntax .., um den Bereich der angegebenen Indizes in einem Datentyp auszuwählen. Weitere Informationen finden Sie im Referenzartikel zum Schleifenausdruck.

F# bietet derzeit intrinsische Unterstützung vom Segmentieren von Zeichenfolgen, Listen, Arrays und mehrdimensionalen Arrays (2D, 3D, 4D). Am häufigsten wird die Segmentierung bei F#-Arrays und -Listen verwendet. Um die Segmentierung zu Ihren benutzerdefinierten Datentypen hinzuzufügen, verwenden Sie die GetSlice-Methode in der Typdefinition oder in einer bereichsinternen Typerweiterung.

Segmentieren von F#-Listen und -Arrays

Die Datentypen, die am häufigsten segmentiert werden, sind F#-Listen und -Arrays. Das folgende Beispiel zeigt, wie Sie Listen segmentieren:

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

Das Segmentieren von Arrays funktioniert genauso wie das Segmentieren von Listen:

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

Vor F# 6 wurde beim Segmentieren die Syntax expr.[start..finish] mit den zusätzlichen . verwendet. Wenn Sie möchten, können Sie diese Syntax nach wie vor verwenden. Weitere Informationen finden Sie unter RFC FS-1110.

Segmentieren von mehrdimensionalen Arrays

F# unterstützt mehrdimensionale Arrays in der F#-Kernbibliothek. Wie bei eindimensionalen Arrays können auch Segmente von mehrdimensionalen Arrays nützlich sein. Die Einführung von zusätzlichen Dimensionen macht jedoch eine etwas andere Syntax erforderlich, damit Sie Segmente von bestimmten Zeilen und Spalten erhalten.

In den folgenden Beispielen wird gezeigt, wie Sie ein 2D-Array segmentieren:

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

Definieren von Segmenten für andere Datenstrukturen

Die F#-Kernbibliothek definiert Segmente für eine eingeschränkte Anzahl an Typen. Wenn Sie Segmente für zusätzliche Datentypen definieren möchten, können Sie dies entweder in der Typdefinition selbst oder in einer Typerweiterung tun.

Hier sehen Sie beispielsweise, wie Sie Segmente für die Klasse ArraySegment<T> definieren, um die bequeme Bearbeitung von Daten zu ermöglichen:

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]

Ein weiteres Beispiel mit den Typen Span<T> und 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|]

Integrierte F#-Segmente schließen das Ende ein

Alle intrinsischen Segmente in F# schließen das Ende ein; die obere Grenze ist also im Segment enthalten. Bei einem bestimmten Segment mit dem Startindex x und dem Endindex y enthält das resultierende Segment den y. Wert.

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

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

Integrierte leere F#-Segmente

In F# ergeben alle Listen, Arrays, Sequenzen, Zeichenfolgen und mehrdimensionale Arrays (2D, 3D, 4D) ein leeres Segment, wenn die Syntax ein Segment erstellen könnte, das nicht vorhanden ist.

Betrachten Sie das folgende Beispiel:

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

Wichtig

C#-Entwickler erwarten in diesen Fällen möglicherweise einen Ausnahmefehler anstatt eines leeren Segments. Das ist eine Designentscheidung, die darauf zurückzuführen ist, dass leere Auflistungen in F# verfasst werden. Eine leere F#-Liste kann mit einer anderen F#-Liste verfasst werden, eine leere Zeichenfolge kann zu einer vorhandenen Zeichenfolge hinzugefügt werden usw. Es kann durchaus vorkommen, dass Segmente basierend auf Werten, die als Parameter übergeben werden, erstellt werden. Die Toleranz von außerhalb der Grenze liegenden > durch die Erstellung einer leeren Sammlung entspricht der kompositorischen Art des F#-Codes.

Segmente mit festem Index für 3D- und 4D-Arrays

Bei 3D- und 4D-F#-Arrays können Sie einen bestimmten Index „fixieren“ und andere Dimensionen mit diesem festen Index segmentieren.

Betrachten Sie zur Veranschaulichung folgendes 3D-Array:

z = 0

x\y 0 1
0 0 1
1 2 3

z = 1

x\y 0 1
0 4 5
1 6 7

Wenn Sie das Segment [| 4; 5 |] aus dem Array extrahieren möchten, verwenden Sie ein Segment mit festem 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]

Die letzte Zeile fixiert die Indizes y und z des 3D-Arrays und übernimmt die restlichen x-Werte, die mit der Matrix übereinstimmen.

Siehe auch