Share via


Sezioni

Questo articolo illustra come prendere sezioni dai tipi F# esistenti e come definire sezioni personalizzate.

In F#, una sezione è un subset di qualsiasi tipo di dati. Le sezioni sono simili agli indicizzatori, ma invece di restituire un singolo valore dalla struttura dei dati sottostante, producono più di uno. Le sezioni usano la .. sintassi dell'operatore per selezionare l'intervallo di indici specificati in un tipo di dati. Per altre informazioni, vedere l'articolo di riferimento sulle espressioni di ciclo.

F# attualmente include il supporto intrinseco per le stringhe di sezionamento, elenchi, matrici e matrici multidimensionali (2D, 3D, 4D). Il sezionamento viene usato più comunemente con matrici ed elenchi F#. È possibile aggiungere il sezionamento ai tipi di dati personalizzati usando il GetSlice metodo nella definizione del tipo o in un'estensione di tipo nell'ambito.

Sezionamento di elenchi e matrici F#

I tipi di dati più comuni che vengono sezionati sono elenchi F# e matrici. Nell'esempio seguente viene illustrato come filtrare gli elenchi:

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

Lo slicing delle matrici è simile a quello degli elenchi di sezionamento:

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

Prima di F# 6, il sezionamento usava la sintassi expr.[start..finish] con l'elemento aggiuntivo .. Se si sceglie, è comunque possibile usare questa sintassi. Per altre informazioni, vedere RFC FS-1110.

Sezionamento di matrici multidimensionali

F# supporta matrici multidimensionali nella libreria principale F#. Come per le matrici unidimensionali, possono essere utili anche sezioni di matrici multidimensionali. Tuttavia, l'introduzione di dimensioni aggiuntive impone una sintassi leggermente diversa in modo da poter accettare sezioni di righe e colonne specifiche.

Gli esempi seguenti illustrano come filtrare una matrice 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}"

Definizione di sezioni per altre strutture di dati

La libreria di base F# definisce le sezioni per un set limitato di tipi. Se si desidera definire sezioni per più tipi di dati, è possibile farlo nella definizione del tipo stesso o in un'estensione del tipo.

Ecco ad esempio come definire le sezioni per la ArraySegment<T> classe per consentire una manipolazione pratica dei dati:

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]

Un altro esempio che usa i Span<T> tipi e 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|]

Le sezioni F# predefinite sono inclusive

Tutte le sezioni intrinseche in F# sono end-inclusive; ovvero, il limite superiore è incluso nella sezione. Per una determinata sezione con indice x iniziale e indice yfinale, la sezione risultante includerà il valore yth .

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

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

Sezioni vuote di F# predefinite

Elenchi F#, matrici, sequenze, stringhe, matrici multidimensionali (2D, 3D, 4D) genereranno tutte una sezione vuota se la sintassi potrebbe produrre una sezione che non esiste.

Si consideri l'esempio seguente:

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

Importante

Gli sviluppatori C# potrebbero aspettarsi che generino un'eccezione anziché produrre una sezione vuota. Si tratta di una decisione di progettazione radicata nel fatto che le raccolte vuote compongono in F#. Un elenco F# vuoto può essere composto con un altro elenco F#, una stringa vuota può essere aggiunta a una stringa esistente e così via. Può essere comune accettare sezioni in base ai valori passati come parametri e tollerare i limiti out-of-bound > producendo una raccolta vuota adatta alla natura composizione del codice F#.

Sezioni di indice fisse per matrici 3D e 4D

Per le matrici F# 3D e 4D, è possibile "correggere" un particolare indice e filtrare altre dimensioni con tale indice fisso.

Per illustrare questo problema, considerare la matrice 3D seguente:

z = 0

x\y 0 1
0 0 1
1 2 3

z = 1

x\y 0 1
0 4 5
1 6 7

Se si desidera estrarre la sezione [| 4; 5 |] dalla matrice, usare una sezione di indice fisso.

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]

L'ultima riga corregge gli y indici e z della matrice 3D e accetta il resto dei x valori che corrispondono alla matrice.

Vedi anche