Udostępnij za pośrednictwem


Wycinki

W tym artykule wyjaśniono, jak wykonywać wycinki z istniejących typów języka F# i jak definiować własne wycinki.

W języku F# wycinek jest podzbiorem dowolnego typu danych. Wycinki są podobne do indeksatorów, ale zamiast zwracać pojedynczą wartość z podstawowej struktury danych, dają one wiele. Wycinki używają .. składni operatora, aby wybrać zakres określonych indeksów w typie danych. Aby uzyskać więcej informacji, zobacz artykuł referencyjny dotyczący wyrażeń pętli.

Język F# ma obecnie wewnętrzną obsługę fragmentowania ciągów, list, tablic i tablic wielowymiarowych (2D, 3D, 4D). Fragmentowanie jest najczęściej używane z tablicami i listami języka F#. Fragmentowanie można dodać do niestandardowych typów danych przy użyciu GetSlice metody w definicji typu lub w rozszerzeniu typu w zakresie.

Fragmentowanie list i tablic języka F#

Najczęściej używane typy danych to listy i tablice języka F#. W poniższym przykładzie pokazano, jak podzielić listy na wycinki:

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

Tablice fragmentowania są podobne do list fragmentowania:

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

Przed F# 6 fragmentowanie używało składni expr.[start..finish] z dodatkowym .elementem . Jeśli wybierzesz tę składnię, nadal możesz użyć tej składni. Aby uzyskać więcej informacji, zobacz RFC FS-1110.

Fragmentowanie tablic wielowymiarowych

Język F# obsługuje tablice wielowymiarowe w podstawowej bibliotece języka F#. Podobnie jak w przypadku tablic jednowymiarowych, wycinki tablic wielowymiarowych mogą być również przydatne. Jednak wprowadzenie dodatkowych wymiarów nakazuje nieco inną składnię, dzięki czemu można wykonywać wycinki określonych wierszy i kolumn.

W poniższych przykładach pokazano, jak podzielić tablicę 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}"

Definiowanie wycinków dla innych struktur danych

Podstawowa biblioteka języka F# definiuje wycinki dla ograniczonego zestawu typów. Jeśli chcesz zdefiniować wycinki dla większej liczby typów danych, możesz to zrobić w samej definicji typu lub w rozszerzeniu typu.

Na przykład poniżej przedstawiono sposób definiowania wycinków dla ArraySegment<T> klasy w celu umożliwienia wygodnego manipulowania danymi:

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]

Inny przykład użycia typów Span<T> i 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|]

Wbudowane wycinki języka F# są kompleksowe

Wszystkie wycinki wewnętrzne w języku F# są kompleksowe; oznacza to, że górna granica jest zawarta w wycinku. W przypadku danego wycinka z indeksem x początkowym i końcowym indeksem ywynikowy wycinek będzie zawierać wartość yth .

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

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

Wbudowane puste wycinki języka F#

Listy języka F#, tablice, sekwencje, ciągi, tablice wielowymiarowe (2D, 3D, 4D) spowodują wygenerowanie pustego wycinka, jeśli składnia może utworzyć wycinkę, która nie istnieje.

Rozważmy następujący przykład:

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

Ważne

Deweloperzy języka C# mogą oczekiwać, że zgłaszają wyjątek, a nie tworzą pustego wycinka. Jest to decyzja projektowa zakorzeniona w tym, że puste kolekcje tworzą się w języku F#. Pusta lista języka F# może składać się z innej listy języka F#. Pusty ciąg można dodać do istniejącego ciągu itd. Często można wykonywać wycinki na podstawie wartości przekazywanych jako parametrów i tolerancyjnej poza granicami > , tworząc pustą kolekcję zgodną z charakterem składowym kodu języka F#.

Wycinki indeksu stałego dla tablic 3D i 4D

W przypadku tablic 3D i 4D języka F# można "naprawić" określony indeks i podzielić inne wymiary na stały indeks.

Aby to zilustrować, rozważmy następującą tablicę 3D:

z = 0

x\y 0 1
0 0 1
1 2 3

z = 1

x\y 0 1
0 100 5
1 6 7

Jeśli chcesz wyodrębnić wycinkę z tablicy, użyj wycinka [| 4; 5 |] indeksu stałego.

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]

Ostatni wiersz naprawia y indeksy i z tablicy 3D i pobiera pozostałe x wartości odpowiadające macierzy.

Zobacz też