Sdílet prostřednictvím


Řezy

Tento článek vysvětluje, jak převést řezy z existujících typů jazyka F# a jak definovat vlastní řezy.

V jazyce F# je řez podmnožinou libovolného datového typu. Řezy se podobají indexerům, ale místo toho, aby z podkladové datové struktury přinesly jednu hodnotu, poskytují více hodnot. Řezy používají syntaxi operátoru .. k výběru rozsahu zadaných indexů v datovém typu. Další informace najdete v článku s referenčními informacemi o výrazech smyčky.

Jazyk F# v současné době podporuje vytváření řezů řetězců, seznamů, polí a multidimenzionálních polí (2D, 3D, 4D). Řezy se nejčastěji používají s poli a seznamy jazyka F#. Řezy můžete přidat do vlastních datových typů pomocí GetSlice metody v definici typu nebo v rozšíření typu v oboru.

Vytváření řezů seznamů a polí jazyka F#

Nejběžnějšími datovými typy, které jsou průřezy, jsou seznamy a pole jazyka F#. Následující příklad ukazuje, jak rozdělit seznamy:

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

Vytváření řezů polí je stejně jako seznamy řezů:

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

Před F# 6 použil řez syntaxi expr.[start..finish] s extra .. Pokud zvolíte tuto syntaxi, můžete tuto syntaxi přesto použít. Další informace najdete v dokumentu RFC FS-1110.

Vytváření řezů multidimenzionálních polí

Jazyk F# podporuje multidimenzionální pole v základní knihovně jazyka F#. Stejně jako u jednorozměrných polí můžou být užitečné i řezy multidimenzionálních polí. Zavedení dalších dimenzí však vyžaduje trochu odlišnou syntaxi, takže můžete vzít řezy konkrétních řádků a sloupců.

Následující příklady ukazují, jak rozdělit 2D pole:

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

Definování řezů pro jiné datové struktury

Základní knihovna jazyka F# definuje řezy pro omezenou sadu typů. Pokud chcete definovat řezy pro více datových typů, můžete to udělat buď v samotné definici typu, nebo v rozšíření typu.

Tady je příklad, jak můžete definovat řezy pro ArraySegment<T> třídu, aby umožňovala pohodlnou manipulaci s daty:

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]

Další příklad použití a Span<T>ReadOnlySpan<T> typů:

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

Předdefinované řezy jazyka F# jsou komplexní

Všechny vnitřní řezy v jazyce F# jsou komplexní; to znamená, že horní mez je součástí řezu. Pro daný řez s počátečním indexem x a koncovým indexem ybude výsledný řez obsahovat hodnotu yth .

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

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

Předdefinované prázdné řezy jazyka F#

Seznamy, matice, sekvence, řetězce, multidimenzionální pole (2D, 3D, 4D) všechna vytvoří prázdný řez, pokud by syntaxe mohla vytvořit řez, který neexistuje.

Představte si následující příklad:

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

Důležité

Vývojáři jazyka C# můžou očekávat, že místo vytvoření prázdného řezu vyvolá výjimku. Toto je rozhodnutí o návrhu založené na faktu, že prázdné kolekce se skládají v jazyce F#. Prázdný seznam jazyka F# lze sestavit s jiným seznamem jazyka F#, prázdný řetězec lze přidat do existujícího řetězce atd. Může být běžné vzít řezy na základě hodnot předaných jako parametry a být odolné vůči mimohraničí > tím, že vytvoří prázdnou kolekci, která odpovídá kompoziční povaze kódu F#.

Řezy s pevným indexem pro 3D a 4D pole

U polí F# 3D a 4D můžete "opravit" určitý index a rozdělit další dimenze s pevným indexem.

Pro ilustraci zvažte následující 3D pole:

z = 0

x\y 0 1
0 0 1
1 2 3

z = 1

x\y 0 1
0 4 5
1 6 7

Pokud chcete extrahovat řez [| 4; 5 |] z pole, použijte řez s pevným indexem.

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]

Poslední řádek opraví y a z indexy 3D pole a vezme zbývající hodnoty x , které odpovídají matici.

Viz také