Tranches
Cet article explique comment prendre des tranches à partir de types F# existants et comment définir vos propres tranches.
Dans F#, une tranche est un sous-ensemble de n’importe quel type de données. Les tranches sont similaires aux indexeurs, mais au lieu de générer une valeur unique à partir de la structure de données sous-jacente, elles en produisent plusieurs. Les tranches utilisent la syntaxe d’opérateur ..
pour sélectionner la plage d’index spécifiée dans un type de données. Pour plus d’informations, consultez article de référence sur les expressions en boucle.
Actuellement, F# prend intrinsèquement en charge les chaînes, listes, tableaux et tableaux multidimensionnels (2D, 3D, 4D). Le découpage est couramment utilisé avec les tableaux et listes F#. Vous pouvez ajouter le découpage à vos types de données personnalisés en utilisant la méthode GetSlice
dans la définition de votre type ou dans une extension de type dans le champ d'application.
Découpage des listes et tableaux F#
Les types de données les plus couramment segmentés sont les listes et tableaux F#. L'exemple suivant montre comment découper des listes :
// 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}"
Le découpage des tableaux est identique à celui des listes :
// 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}"
Avant F# 6, le découpage utilisait la syntaxe expr.[start..finish]
avec l'extension .
. Si vous le choisissez, vous pourrez toujours utiliser cette syntaxe. Pour plus d’informations, consultez RFC FS-1110.
Découpage de tableaux multidimensionnels
F# prend en charge les tableaux multidimensionnels dans la bibliothèque principale F#. Comme pour les tableaux unidimensionnels, les tranches de tableaux multidimensionnels peuvent également être utiles. Toutefois, l’introduction de dimensions supplémentaires impose une syntaxe légèrement différente pour que vous puissiez prendre des tranches de lignes et de colonnes spécifiques.
Les exemples suivants montrent comment découper un tableau 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}"
Définir des tranches pour d’autres structures de données
La bibliothèque principale F# définit des tranches pour un ensemble de types limité. Si vous souhaitez définir des tranches pour plus de types de données, vous pouvez le faire dans la définition de type elle-même ou dans une extension de type.
Par exemple, voici comment définir des tranches pour la classe ArraySegment<T> afin de permettre une manipulation de données plus pratique :
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]
Autre exemple utilisant les types Span<T> et 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|]
Les tranches F# intégrées sont inclusives de bout en bout
Toutes les tranches intrinsèques en F# sont inclusives de bout en bout ; autrement dit, la limite supérieure est incluse dans la tranche. Pour une tranche donnée avec l’index x
de début et l’index y
de fin, la tranche résultante inclut la valeur yth.
// Define a new list
let xs = [1 .. 10]
printfn $"{xs[2..5]}" // Includes the 5th index
Tranches F# intégrées vides
Les listes F#, tableaux, séquences, chaînes, et tableaux multidimensionnels (2D, 3D, 4D) produisent tous une tranche vide si la syntaxe peut produire une tranche qui n’existe pas.
Prenons l’exemple suivant :
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)]
Important
Les développeurs C# pourraient s’attendre à ce qu’ils génèrent une exception plutôt que de produire une tranche vide. Il s'agit d'une décision de conception ancrée dans le fait que les collections vides se composent en F#. Une liste F# vide peut être composée avec une autre liste F#, une chaîne vide peut être ajoutée à une chaîne existante, et ainsi de suite. Il peut être courant de prendre des tranches basées sur des valeurs transmises en tant que paramètres, et le fait de tolérer les dépassements de limites > en produisant une collection vide correspond à la nature compositionnelle du code F#.
Tranches d’index fixes pour les tableaux 3D et 4D
Pour les tableaux F# 3D et 4D, vous pouvez « corriger » un index particulier et segmenter d’autres dimensions avec cet index fixe.
Pour illustrer cela, considérez le tableau 3D suivant :
z = 0
x\y | 0 | 1 |
---|---|---|
0 | 0 | 1 |
1 | 2 | 3 |
z = 1
x\y | 0 | 1 |
---|---|---|
0 | 4 | 5 |
1 | 6 | 7 |
Si vous souhaitez extraire la tranche [| 4; 5 |]
du tableau, utilisez une tranche d’index fixe.
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]
La dernière ligne corrige les index y
et z
du tableau 3D, et prend le reste des valeurs x
correspondant à la matrice.